Какой тип приведения подходит для преобразования из unsigned char * в char *? - PullRequest
2 голосов
/ 19 июня 2020

Когда я записываю данные в буфер и из буфера для сохранения в файл, я обычно использую std::vector<unsigned char> и отношусь к этим беззнаковым символам так же, как к байтам для записи чего-либо, так:

int sizeoffile = 16;
std::vector<unsigned char> buffer(sizeoffile);

std::ifstream inFile("somefile", std::ios::binary | std::ios::in);
inFile.read(buffer.data(), sizeoffile); // Argument of type unsigned char* is incompatible
                                        // with parameter of type char*

Первому аргументу ifstream::read() нужен указатель char, но мой векторный буфер - unsigned char. Какой тип приведения здесь подходит для чтения данных в мой буфер? По сути, это от char* до unsigned char*. Я могу использовать reinterpret_cast или приведение в стиле C, но это заставляет меня думать, что я делаю что-то не так, поскольку это не очень часто рекомендуется. Я сделал неправильный выбор типа данных (unsigned char) для своего буфера?

Ответы [ 2 ]

6 голосов
/ 19 июня 2020

Самым безопасным будет не использовать приведение напрямую, а использовать вспомогательный шаблон, который ограничивается преобразованием между типами с совместимыми представлениями.

template<typename T, typename U>
treat_as(U* ptr) -> enable_if_t< is_same_type_v< remove_unsigned<T>, remove_unsigned<U> >, T >*
{ return reinterpret_cast<T*>(ptr); }

, а затем

inFile.read(treat_as<char>(&buffer[0]), sizeoffile); 

Если когда-нибудь тип вектора изменится на unsigned wchar_t, этот вызов завершится ошибкой, а reinterpret_cast тихо начнет делать неправильные вещи.

1 голос
/ 19 июня 2020

Сходство между char и unsigned char здесь отвлекает: для любого тривиально копируемого типа вы можете reinterpret_cast его адрес на char* для заполнения через istream::read, потому что char имеет специальное разрешение на псевдоним любого типа. (Возможно, он должен работать даже для таких типов, как std::tuple<int> с тривиальными копирующими конструкторами , но с нетривиальными операторами присваивания копии, но стандарт этого не обещает. С другой стороны, указатели легко копируются, но это не означает, что вы можете загружать значения указателей из других исполнений!)

Вы, конечно, должны использовать sizeof в целом; было бы разумно использовать его, даже если он 1, для защиты от будущих изменений типа.

...