为什么 printf 对于不同的编译器设置 64 和 32 显示错误的 int 变量值?

Why printf shows wrong value for int variable for different compiler settings 64 vs 32?

我有以下程序。

int main () {
    int a = 1;
    long long b = 100000000;
    printf("size of a is: %d \t sizeof b is:%d  \n",sizeof(a),sizeof(b));
    printf("a= %d b=%d a=%d \n", a, b, a);
    printf("a= %d b=%Ld a=%d \n", a, b, a);
    b = 10000000000;
    printf("a= %d b=%d a=%d \n", a, b, a);
    printf("a= %d b=%Ld a=%d \n", a, b, a);
}

当我用gcc -m32编译它时,输出是

size of a is: 4      sizeof b is:8  
a= 1 b=100000000 a=0 
a= 1 b=100000000 a=1 
a= 1 b=1410065408 a=2 
a= 1 b=10000000000 a=1 

但是当用 gcc -m64 编译时输出是。

size of a is: 4      sizeof b is:8  
a= 1 b=100000000 a=1 
a= 1 b=100000000 a=1 
a= 1 b=1410065408 a=1 
a= 1 b=10000000000 a=1 

为什么打印第三个 printf 参数 (a) 时显示错误值?

我的 gcc 版本是

priyanka@priyanka-N551JB:~$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper
Target: x86_64-linux-gnu

您必须使用 %lld 打印 long long 个值。您不能使用 %d 打印它们。如果您尝试使用 %d 打印它们,它将不起作用。 (事实证明 %Ld 也不对,尽管听起来 gcc 让你得逞了。)

数字 10000000000 需要 34 位来表示。正如您所发现的,它不适合 16 位或 32 位普通 int。但是,它将适合 64 位 long long int.

很难确切知道当您尝试使用 %d 打印 64 位 long long 时会发生什么。您可以想象将 8 个字节压入堆栈,然后 %d 弹出其中的 4 个字节。因此,其他四个仍留在堆栈中,因此它们是第三个 %d 的弹出值,而不是 a 的实际值。这不一定是实际发生的事情,实际上它可能比这更复杂。复杂性可能很容易取决于您是在 32 位还是 64 位模式下编译。


这最终是一个重要观点的小而简单的说明:当程序使用未定义的行为时,程序的 所有 方面可能会变得未定义。当你做了一些真正错误的事情时,比如尝试使用 %d 打印 blong long 值,出问题的不仅仅是 b 的值打印不正确 - - 其他事情也会出错。

打个比方。假设你买了一辆全新的赛车,轮胎又薄又快。售货员提醒您,这是一辆公路自行车,只能在平坦的柏油路上骑行。销售员警告说,如果你想在越野时骑它,如果你撞到石头,轮胎很可能会爆裂。

现在,假设您骑自行车离开公路。假设你翻过一块岩石,轮胎爆裂,因此你失去控制,撞车,车把弯曲,前额也被割伤。假设你回到自行车店说,"Okay, I rode the bike off the road, and the tire popped like you said. But can you explain why the handlebars got bent, and I got this cut on my head?"