我正在做一些数学运算,然后像这样打印一个带符号的长整数:
file1.c
#include <stdio.h>
int main (int argc, char *argv[])
{
long my_signed_integer = 9999L * 9999L * 9999L * 9999L;
printf("This is my signed integer %ld.\n", my_signed_integer);
return 0;
}
生成文件
CFLAGS=-Wall -g
all: file1
clean:
rm -f file1
我试图看看在我的编译器不向我抛出错误的情况下我能走多远,每次乘法都加一个 9999L
,然后运行:
make
./file1.c
看看会发生什么。
4 次
当使用 9999L
4 次时(如上例),我得到:
这是我的有符号整数 9996000599960001。
没有任何警告。
5 次
使用 9999L
5 次,我收到 1 个警告:
warning: overflow in expression; result is 7716289630452291919 with type 'long'
[-Winteger-overflow]
但是文件还是编译通过了,最终的结果是:
这是我的有符号整数 7716289630452291919。
6 次
使用 9999L
6 次,我收到 2 条警告 - 一条是负数:
warning: overflow in expression; result is 7716289630452291919 with type 'long'
[-Winteger-overflow]
long my_signed_integer = 9999L * 9999L * 9999L * 9999L * 9999L * 9999L;
^
warning: overflow in expression; result is -7550445434587511647 with type 'long'
[-Winteger-overflow]
long my_signed_integer = 9999L * 9999L * 9999L * 9999L * 9999L * 9999L;
唉,文件仍然编译,结果是:
这是我的有符号整数 -7550445434587511647。
随着我添加越来越多的整数,这种模式继续存在 - 我每次都会收到另一个警告。
首先,有人可以解释为什么编译器不会崩溃并拒绝编译文件吗?显然存在溢出 - 为什么可以容忍这种情况,而其他情况 - 例如乘以非常大的数字 - 会使它崩溃?
还有,为什么最后的结果是负整数?
最佳答案
有符号整数类型的溢出是 undefined behavior按照 C 标准。所以编译器可以自由地生成它想要的任何行为。这也意味着是否生成警告是自由的。
在实践中,在使用 2 的整数补码表示的托管实现中,溢出将表现得好像参数是无符号的(因此减少模 2^(位长度))并且结果被解释为有符号。
在您的特定情况下,long
似乎是 64 位类型。因此,将 9999L
本身乘以 4 次适合该类型,但再多一点就会溢出。您获得的值是解释为 signed long
的结果的最低 64 位。
5次的情况下,恰好高位没有置位,所以结果显示为正。在6次的情况下,设置了高位,所以显示为负数。
关于c - 带符号的长整数随着它的增长变成负数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43413311/