Я не понимаю, как порядок байтов меняет порядок элементов массива uint32_t
при преобразовании в uint64_t
и наоборот.
Если я имею дело с байтами, хранящимися в массиве uint8_t из 8 элементов, если я напрямую преобразую его в uint64_t
, используя приведение указателя и разыменование следующим образом:
uint8_t array[8] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0xb0, 0xa0};
uint64_t u = *(uint64_t *)array;
В системе с прямым порядком байтов u
будет равно 0xa0b0ffeeddccbbaa
Но если у меня есть такой массив uint32_t
:
uint32_t arr[2] = {0xaabbccdd, 0xeeffb0a0} ;
uint64_t U = *(uint64_t *)arr;
В системе с прямым порядком байтов U
становится 0xeeffb0a0aabbccdd
Я интуитивно понимаю первый случай, но второй, с uint32_t
, сбивает с толку!
У меня проблемы с визуализацией расположения памяти во время преобразования, в последнем случае...
Каждая помощь будет принята с благодарностью!
Кроме того, «В системе с прямым порядком байтов u будет равно 0xa0b0ffeeddccbbbaa» -> код *(uint64_t *)array
рискует вызвать проблемы с выравниванием.
@WhozCraig Не могли бы вы уточнить больше? :)
@chux-ReinstateMonica Можете ли вы подробнее рассказать о проблемах выравнивания?
Пример говорил бы громче, чем что-либо еще. Думайте о том, что вы делаете, но в обратном направлении. Посмотрите на это. Подумайте, что делает представление с порядком байтов с каждым из этих значений uint32_t
в этом массиве из двух.
Endianess применяется индивидуально к каждому целому числу от 16 бит или больше. То есть на машине с прямым порядком байтов 32-битное целое число 0xaabbccdd
хранится как dd cc bb aa
.
Таким образом, массив из двух 32 целых чисел uint32_t [2]
со значениями 0x11223344
и 0x55667788
хранится как 44 33 22 11
и 88 77 66 55
соответственно. В массиве элементы гарантированно хранятся непрерывно, поэтому в этом случае память будет выглядеть как 44 33 22 11 88 77 66 55
.
Однако 64-битное целое число 0x1122334455667788
сохраняется как 88 77 66 55 44 33 22 11
, потому что, опять же, порядок байтов применяется индивидуально к каждому целому числу. Вот почему вы не можете переинтерпретировать структуру памяти двух 32-битных целых чисел как 64-битное целое число на машинах с прямым порядком байтов.
Однако, если бы ЦП был с обратным порядком байтов, uint32_t [2]
был бы сохранен как: 11 22 33 44 55 66 77 88
, а затем получается то же представление, что и uint64_t
со значением 0x1122334455667788
.
В качестве примечания: преобразования *(uint64_t *)array
в вашем коде представляют собой неопределенное поведение, поскольку они нарушают строгое сглаживание указателей и, возможно, также могут привести к смещению. Для безопасного преобразования между различными типами памяти вам необходимо использовать битовые сдвиги, memcpy
или union
.
Большое спасибо за ваш ответ! Благодаря вашему ответу я очень четко понял концепцию! :) Но я использовал эту технику преобразования из соображений эффективности. Но по вашему совету я буду использовать memcpy
/ union
! :)
Endianess захватывает с самого начала на
uint32_t arr[2]
. Оба этих значенияuint32_t
хранятся в представлении endian для конкретной платформы. Это не относится к первому образцу и базовому массивуuint8_t
. Считают, что.