我正在做一些数学运算,然后打印一个有符号的长整数:
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次时(如上例所示),我得到:
This is my signed integer 9996000599960001.
没有任何警告。
5次
使用9999L
5次,我收到1次警告:
warning: overflow in expression; result is 7716289630452291919 with type 'long'
[-Winteger-overflow]
但文件仍在编译,最终结果是:
This is my signed integer 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;
唉,文件仍在编译,结果是:
This is my signed integer -7550445434587511647.
随着我添加越来越多的整数,这种模式仍在继续 - 我每次都会收到另一个警告。
首先,有人可以解释为什么编译器不会崩溃并拒绝编译文件?显然有一个溢出 - 为什么这是容忍的,而其他情况 - 例如乘以非常大的数字 - 会让它崩溃?
另外,为什么最终结果是负整数?
答案 0 :(得分:6)
根据C标准,有符号整数类型的溢出为undefined behavior。因此编译器可以自由地生成它想要的任何行为。这也意味着可以自由生成警告。
实际上,在使用2的整数补码表示的托管实现上,溢出的行为就好像参数是无符号的(因此减少的模2 ^(位长))并且结果被解释为签名。
在您的特定情况下,long
似乎是64位类型。因此,将9999L
自身乘以4次适合该类型,但不再需要溢出。您获得的值是解释为signed long
的结果的最低64位。
在5次的情况下,高阶位碰巧没有被设置,因此结果显示为正。在6次的情况下,高位被设置,因此它显示为负。