我正在做一些數學,然後打印符號長整型,像這樣:簽名的長整數變成負數,因爲它增長?
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;
}
的Makefile
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.
隨着我添加越來越多的整數,這種模式會繼續下去 - 我每次都會收到另一個警告。
首先,有人可以解釋爲什麼編譯器不會崩潰並拒絕編譯文件?顯然有一個溢出 - 爲什麼這是容忍的,其他情況 - 比如乘數非常大的數字 - 會使它崩潰?
另外,爲什麼是最終的結果負整數?
帶符號的整數溢出是未定義的行爲,換句話說,「行爲,使用非國際標準不要求的不可移植或錯誤的程序結構或錯誤數據」。因此,編譯器可以自由地拒絕編譯,可以發出警告,或者可以做任何喜歡的事情,例如編譯一個格式化硬盤的程序(不太可能)。用'-Werror'你會在這種情況下得到一個錯誤而不是警告。 –
爲了擴展@IljaEverilä寫道:沒有要求實現來記錄它如何hebaves,也不會產生相同的行爲的代碼的不同部分。這意味着檢查**具體發生的事情是無用的。你必須解決這個問題。 – Olaf
至於爲什麼在這種特殊情況下溢出會導致負數,您的系統可能會使用[2的補碼錶示](https://en.m.wikipedia.org/wiki/Two%27s_complement),但@Olaf指出你不能依賴這種事情發生。 –