Есть ли хороший способ конвертировать из без знака char * в char *? - PullRequest
1 голос
/ 17 января 2011

В те дни я много читал о reinterpret_cast<> и о том, как его использовать (и избегать этого в большинстве случаев).

Хотя я понимаю, что использование reinterpret_cast<> для приведения, скажем,От unsigned char* до char* определяется реализация (и, следовательно, непереносимая ), похоже, что эффективно не может преобразовать один в другой.

Допустим, я использую библиотеку, которая имеет дело с unsigned char*, для обработки некоторых вычислений.Внутренне, я уже использую char* для хранения своих данных (и я не могу изменить их, потому что это убило бы щенков, если бы я это сделал).

Я бы сделал что-то вроде:

char* mydata = getMyDataSomewhere();
size_t mydatalen = getMyDataLength();

// We use it here
// processData() takes a unsigned char*
void processData(reinterpret_cast<unsigned char*>(mydata), mydatalen);

// I could have done this:
void processData((unsigned char*)mydata, mydatalen);
// But it would have resulted in a similar call I guess ?

Если я хочу, чтобы мой код был легко переносимым, похоже, у меня нет другого выбора, кроме как сначала скопировать свои данные.Что-то вроде:

char* mydata = getMyDataSomewhere();
size_t mydatalen = getMyDataLength();
unsigned char* mydata_copy = new unsigned char[mydatalen];
for (size_t i = 0; i < mydatalen; ++i)
  mydata_copy[i] = static_cast<unsigned char>(mydata[i]);

void processData(mydata_copy, mydatalen);

Конечно, это крайне неоптимально, и я даже не уверен, что оно более портативное, чем первое решение.

Так что вопрос в том, что бы выделать в этой ситуации иметь переносимый код?

Ответы [ 4 ]

6 голосов
/ 17 января 2011

Портативный это на практике вопрос.Таким образом, reinterpret_cast для конкретного использования преобразования между char* и unsigned char* является переносимым.Но все же я бы обернул это использование в пару функций вместо того, чтобы делать reinterpret_cast непосредственно в каждом месте.

Не переусердствуйте, вводя неэффективность при использовании языка, где почти все бородавки (включая одиноб ограниченных гарантиях для reinterpret_cast) в поддержку эффективности.

Это будет работать против духа языка при соблюдении буквы.

Приветствия и hth.

2 голосов
/ 17 января 2011

Разница между типами char и unsigned char заключается лишь в семантике данных.Это влияет только на то, как компилятор выполняет арифметику с элементами данных любого типа.Тип char сообщает компилятору, что значение старшего бита следует интерпретировать как отрицательное, так что компилятор должен выполнять арифметику с двумя дополнениями.Поскольку это единственное различие между этими двумя типами, я не могу представить сценарий, в котором reinterpret_cast <unsigned char*> (mydata) будет генерировать вывод, отличный от (unsigned char*) mydata.Более того, нет смысла копировать данные, если вы просто информируете компилятор об изменении в семантике данных, т. Е. О переключении со знаковой арифметики на неподписанную.

РЕДАКТИРОВАТЬ: Хотя вышеЭто верно с практической точки зрения, я должен отметить, что стандарт C ++ гласит, что char, unsigned char и sign char являются тремя различными типами данных.§ 3.9.1.1:

Объекты, объявленные как символы (char), должны быть достаточно большими для хранения любого члена базового набора символов реализации.Если символ из этого набора хранится в символьном объекте, интегральное значение этого символьного объекта равно значению буквальной формы одного символа этого символа.Это зависит от реализации, может ли объект char содержать отрицательные значения.Символы могут быть явно объявлены как неподписанные или подписанные.Обычный символ, символ со знаком и символ без знака - это три различных типа, которые в совокупности называются узкими символами.Символ, подписанный символ и неподписанный символ занимают одинаковый объем памяти и имеют одинаковые требования выравнивания (3.11);то есть они имеют одинаковое объектное представление.Для узких типов символов все биты представления объекта участвуют в представлении значения.Для беззнаковых типов символов без знака все возможные битовые комбинации представления значения представляют собой числа.Эти требования не распространяются на другие типы.В любой конкретной реализации простой объект типа char может принимать либо те же значения, что и знак со знаком, либо без знака;какой из них определяется реализацией.

1 голос
/ 17 января 2011

Для совместимости с С типы unsigned char* и char* имеют дополнительные ограничения.Смысл в том, что такие функции, как memcpy(), должны работать, и это ограничивает свободу, которой обладают компиляторы.(unsigned char*) &foo должен по-прежнему указывать на объект foo.Поэтому не беспокойтесь в этом конкретном случае.

1 голос
/ 17 января 2011

Примените приведение, на практике все нормально.

Я просто хочу добавить, что это:

for (size_t i = 0; i < mydatalen; ++i)
  mydata_copy[i] = static_cast<unsigned char>(mydata[i]);

, не будучи неопределенным поведением, может изменить содержимое вашей строки намашины без 2-х дополнений арифметики.Обратное было бы неопределенным поведением.

...