为什么这个程序输出8589934593而不是4294967298

Why does this program output 8589934593 instead of 4294967298?

本文关键字:4294967298 8589934593 输出 程序 为什么      更新时间:2023-10-16

这是一个滥用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}中的两个整数构成了structlong a的空间。

但我的问题是,既然现在{1,2}组成了a,二进制内存对齐应该是00000000000000000000000000000001 00000000000000000000000000000010,它应该给出十进制格式的4294967298。但是,实际打印输出的是8589934593,即00000000000000000000000000000010 00000000000000000000000000000001。看起来12的位置实际上是交换的。

为什么会发生这种情况?

在小端序机器上,{ 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)