为什么这个程序输出8589934593而不是4294967298
Why does this program output 8589934593 instead of 4294967298?
这是一个滥用void*
ptr的示例(这本身就是一种糟糕的编码实践),但当我研究内存细节时,它会变得很有趣。
#include <iostream>
using namespace std;
typedef struct {
long a;
void print() {
std::cout << a;
}
} st;
int main() {
int t[2] = {1,2};
void* p = t;
st* spt = (st*) p;
spt->print();
return 0;
}
由于long
是64位,而int
是32位,因此t、{1,2}
中的两个整数构成了struct
中long a
的空间。
但我的问题是,既然现在{1,2}
组成了a
,二进制内存对齐应该是00000000000000000000000000000001 00000000000000000000000000000010
,它应该给出十进制格式的4294967298
。但是,实际打印输出的是8589934593
,即00000000000000000000000000000010 00000000000000000000000000000001
。看起来1
和2
的位置实际上是交换的。
为什么会发生这种情况?
在小端序机器上,{ 1, 2 }
数组在内存中按以下字节序列排列
01 00 00 00 02 00 00 00 // addresses increase from left to right
当重新解释为64位小端值时,它产生8589934593
。
在big-endian机器上,与布局相同的阵列
00 00 00 01 00 00 00 02 // addresses increase from left to right
当重新解释为64位大端序值时,它产生4294967298
。
因此,您的实验只是表明您正在一台小型endian机器上运行代码。这就是它的全部。
有趣的事实。从数字上讲,答案可以简化为的指数
2^n + 1: n=33
哪个是
2^(33)+1 = 8589934593
并且在二进制中表示为
1000000000000000000000000000000001
可爱的二进制;具有32个零,在这种情况下为n-1。
我用更可移植的方式重写您的代码,它需要c++11:
#include <cstdint>
#include <iostream>
int main()
{
union {
uint32_t t[2];
uint64_t a;
} val;
val.t[0] = 1;
val.t[1] = 2;
std::cout << val.a << ", " << std::hex << val.a << 'n';
}
我的amd64机器上的输出是:
858993459320000000001
并且它似乎完全有效,等于uint64_t(2) << 32 | uint64_t(1)