Хотя поведение, которое вы видите, как и говорили другие, не определено стандартом C ++, кажется, что останавливаться на этом не очень полезно. То, что вы видите, это именно то, что вы должны ожидать от простого перевода вашего исходного кода в машинный код разумным компилятором для архитектуры с прямым порядком байтов в системе с 64-битным или меньшим адресным пространством, которое разрешает не выровненные обращения и чьи «длинные» тип 32 бит. Оптимизирующий компилятор может делать странные вещи, поскольку он обнаруживает, что вы делаете что-то с неопределенным поведением, но с отключенной оптимизацией или при использовании того, что я бы назвал * Компилятор 1006 * разумный даже при высокой оптимизации результаты, которые вы видите, - это именно то, чего вы ожидаете от такой системы.
Вероятно, ваша главная причина путаницы связана с порядком байтов. Ваш массив arr[]
, вероятно, не хранится в байт-памяти, как вы ожидаете. Здесь я определил массивы с одинаковой разметкой байтов двумя различными способами:
// 281474976710656 is 0x0001000000000000
int64_t arr[] = { 0x0001000000000000, 0x000000007fffffff }; // { 281474976710656, LONG_MAX };
// ...on a little endian machine (like x86), the bytes of that array are stored like this:
int8_t arr8[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00 };
В формате с прямым порядком байтов (очень распространенный формат) аппаратное обеспечение интерпретирует младший байт как младший порядковый (наименее значимый) байт и байт с самым высоким адресом в качестве байта самого высокого порядка (наиболее значимого). Хотя это более запутанно, если посмотреть на дамп памяти, у этого порядка есть небольшое потенциальное преимущество в производительности: когда вы приводите многобайтовое скалярное значение от более широкой ширины к меньшей ширине (например, от int64_t
до int32_t
), на В системе с прямым порядком байтов адрес в памяти меньшего объекта совпадает с адресом более крупного (uncast) объекта. В системе с прямым порядком байтов адреса обязательно различны. В системе с прямым порядком байтов, если компилятор желает оптимизировать доступ для чтения скалярного значения, которое будет приведено к меньшему типу, он может просто выдать инструкцию для чтения меньшего типа в первую очередь с того же адреса, что и он. прочитал бы больший тип. В системе с прямым порядком байтов компилятор должен будет выполнить дополнительную инструкцию для настройки адреса перед его чтением (или выполнить более крупную инструкцию, которая корректирует адрес при его чтении). (Или прочитайте весь более крупный объект и затем замаскируйте верхнюю часть; как бы вы ни смотрели на него в системе с прямым порядком байтов, она не может быть более эффективной, чем та же самая операция в другой идентичной системе с прямым порядком байтов. )
В любом случае, вернитесь к своему коду ...
Когда ваш код преобразует arr
в int64_t
и добавляет 1 к это, то, что вы получите, это адрес полужирного байта:
int8_t arr8 [] = {0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00};
Итак, когда вы разыгрываете это как (int8_t *)
и разыменовываете его, вы чтение одного байта по этому адресу и получение 0x00
.
Когда ваш код затем использует тот же указатель nal
, что и (int64_t *)
, потому что в вашей системе разрешен доступ без выравнивания , вы получите 8 жирный шрифт байт ниже ...
int8_t arr8 [] = {0x00, 0x00 , 0x00 , 0 x00 , 0x00 , 0x00 , 0x01 , 0x00 , 0xff , 0xff, 0xff, 0x7f , 0x00, 0x00, 0x00, 0x00};
... но оборудование считывает его в формате с прямым порядком байтов. Вот почему вы получаете ff0001000000000000
вместо 100ff
...
... и это еще один момент: я не уверен, почему вы ожидали 1000000000000FF
; Я не думаю, что это разумное ожидание в любой системе (несмотря на неопределенное поведение). В системе с прямым порядком байтов схема байтов вашего массива arr[]
будет выглядеть следующим образом:
int8_t arr8[] = { 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff };
И если вы разыгрываете nal
как (int64_t)
в системе с прямым порядком байтов (все остальные черты при одинаковом разрешении (в том числе разрешении доступа без выравнивания) вы получите полужирный байт ниже ...
int8_t arr8 [] = {0x00, 0x01 , 0x00 , 0x00 , 0x00 , 0x00, 0x00 , 0x00 , 0x00 , 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff};
. ..читается на оборудовании в формате с прямым порядком байтов, давая вам результирующую строку 100000000000000
.