为什么 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
打印 b
的 long 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?"
我有以下程序。
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
打印 b
的 long 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?"