У меня есть следующий код:
std::vector<short> vec{ 0, 2, 0, 4 };
int* lpvec = reinterpret_cast<int*>(&vec[0]);
(Скомпилировано под VC12: короткие 2 байта, int 4 байта) Я думаю, что он будет производить:
lpvec[0] = 2,
lpvec[1] = 4
но это меня удивляет и выносит
lpvec[0] = 2 * 2^16 + 0 = 131072,
lpvec[1] = 4 * 2^16 + 0 = 262144
Я сказал контр-интуитивно, потому что я думаю, что вектор шорт выкладывается в памяти по следующей схеме:
+---------+---------+---------+---------+
| 2 bytes | 2 bytes | 2 bytes | 2 bytes |
+---------+---------+---------+---------+
| 0 | 2 | 0 | 4 |
+---------+---------+---------+---------+
поэтому int будет выглядеть одинаково, но занимает в два раза больше места:
+-------------+------------+
| 4 bytes | 4 bytes |
+-------------+------------+
| 0*2^16 + 2 | 0*2^16 + 4 |
+-------------+------------+
Кто-нибудь просветит меня, почему я ошибаюсь?
Ой, это не круто...
То, что вы делаете, вызывает неопределенное поведение.
Приведение short*
в int*
нарушало бы правила псевдонимов, но в первую очередь "неожиданный" результат был обусловлен реализацией, определяемой конъюнкцией интегральных значений.
Little- против Big-Endian
"Endianness" - это порядок байтов (представляющих значение), хранящихся внутри интегрального типа, в этом случае int
.
Кажется, что ваша платформа использует Little- endian; это означает, что младший байт сохраняется первым, а ваш ожидаемый результат зависит от реализации с использованием big-endian; который, как указано, не соответствует действительности.
Ваша реализация хранит short { 2 }
как [0x02][0x00]
, что сделает int
указывает lpvec
эквивалентный [0x00][0x00][0x02][0x00]
.
В расчетах участвуют, так как ваша платформа использует big-endian:
(2^0 * 0) + (2^8 * 0) + (2^16 * 2) + (2^24 * 0) = 131072
Примечание: вышесказанное предполагает, что байт имеет ширину 8
бит, что также определяется реализацией.