2011-01-16 6 views
1

Я много читал в те дни около reinterpret_cast<> и как он должен использовать его (и избегать его в большинстве случаев).Есть ли хороший способ конвертировать из unsigned char * в char *?

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

Допустим, я использую библиотеку, которая имеет дело с unsigned char*, для обработки некоторых вычислений. Internaly, я уже использую 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); 

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

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

+1

Непросто использовать naked char * в программе на C++ для чего угодно, кроме того, что конкретный листинг (между unsigned char *, char * и/или подписанный char *) сам по себе очень портативен. –

ответ

6

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

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

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

Cheers & hth.

2

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

EDIT: Хотя вышеизложенное верно с практической точки зрения, я должен отметить, что стандарт C++ утверждает, что char, unsigned char и sign char являются тремя различными типами данных. § 3.9.1.1:

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

+0

Я думаю, что ты прав. – bbg

+0

@bbg, затем проголосуйте, пожалуйста – ThomasMcLeod

1

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

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

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

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

+0

Нет необходимости в явном цикле, когда он уже находится в C++/STL '#include ': 'std :: copy (mydata, mydata + mydatalen, mydata_copy)'. – ephemient

1

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

Смежные вопросы