Могу ли я преобразовать unsigned char* в unsigned int*?

error: invalid static_cast from type ‘unsigned char*’ to type ‘uint32_t* {aka unsigned int*}’
     uint32_t *starti = static_cast<uint32_t*>(&memory[164]);

Я выделил массив символов и хочу прочитать 4 байта как 32-битное целое число, но получаю ошибку компилятора. Я знаю, что могу сдвигать биты, например:

(start[0] << 24) + (start[1] << 16) + (start[2] << 8) + start[3];

И он будет делать то же самое, но это много дополнительной работы.

Можно ли как-то просто преобразовать эти четыре байта в целое число?


person David Mulder    schedule 31.03.2014    source источник
comment
Ага. uint32_t val = *(uint32_t*)((void*)(memory+164));   -  person IdeaHat    schedule 31.03.2014
comment
Посмотрите здесь: stackoverflow.com/questions/2473628/   -  person Marius    schedule 31.03.2014
comment
Надо заметить, что делать это не очень c++-й. Например, если «память» поступает из файла или из сети, вам нужно беспокоиться о порядке байтов.   -  person mic_e    schedule 31.03.2014
comment
@mic_e Я работаю над бинарным транслятором из pa-risc в x86_64. Я прекрасно понимаю, что мне нужно следить за порядком байтов :)   -  person David Mulder    schedule 31.03.2014
comment
@MadScienceDreams Нет, пожалуйста, не используйте приведения в стиле C.   -  person Konrad Rudolph    schedule 31.03.2014
comment
Это называется каламбуром типа, поскольку на самом деле это незаконно. Вы можете привести указатель через reinterpret_cast, и он гарантированно сработает. Однако вы не всегда можете разыменовать его. Ваше решение с битовым сдвигом в порядке, как и memcpy для объекта uint32_t. Рекомендуем вам также прочитать это.   -  person jrok    schedule 31.03.2014
comment
@KonradRudolph Я понимаю ненависть, но ... это код C, это низкоуровневый, немного вертящийся, скрежещущий зубами, отбрасывание к дьяволу, проверка сборки, код. И нам НУЖНО это время от времени, потому что это часто самый быстрый способ сделать что-то. Мы можем обернуть reinterpret_cast‹uint32_t*›, чтобы вам стало лучше, но это не изменит того, что мы делаем!   -  person IdeaHat    schedule 31.03.2014
comment
@MadScienceDreams Да, меня беспокоит ясность. reinterpret_cast просто гораздо более подробно описывает, что он делает.   -  person Konrad Rudolph    schedule 01.04.2014


Ответы (4)


static_cast предназначен для использования в "хороших" приведениях, таких как double -> int. Вы должны использовать reinterpret_cast:

uint32_t *starti = reinterpret_cast<uint32_t*>(&memory[164]);

Или, если вы готовы, приведения в стиле C:

uint32_t *starti = (uint32_t*)&memory[164];
person Community    schedule 31.03.2014

Да, вы можете преобразовать значение указателя unsigned char* в uint32_t* (используя приведение в стиле C или reinterpret_cast), но это не означает, что вы обязательно можете использовать результат.

Результат такого преобразования может не указывать на адрес, правильно выровненный для хранения объекта uint32_t. Например, unsigned char* может указывать на нечетный адрес; если uint32_t требует даже выравнивания, у вас будет неопределенное поведение при попытке разыменовать результат.

Если вы можете каким-то образом гарантировать, что unsigned char* действительно указывает на правильно выровненный адрес, вы должны быть в порядке.

person Keith Thompson    schedule 31.03.2014

Я привык к BDS2006 C++, но в любом случае это должно нормально работать и на других компиляторах.

char memory[164];
int *p0,*p1,*p2;
p0=((int*)((void*)(memory)));    // p0 starts from start
p1=((int*)((void*)(memory+64))); // p1 starts from 64th char
p2=((int*)((void*)(&memory[64]))); // p2 starts from 64th char
person Spektre    schedule 31.03.2014

Вы можете использовать reinterpret_cast, как предложил faranwath, но, пожалуйста, поймите риск, связанный с этим путем.

Ценность того, что вы получите обратно, будет радикально отличаться в системе с прямым порядком байтов и в системе с прямым порядком байтов. Ваш метод сработает в обоих случаях.

person R Sahu    schedule 31.03.2014