GCC產生浮動代碼,對於下面的代碼引發SIGFPE
:INT_MIN%-1是否會產生未定義的行爲?
#include <limits.h>
int x = -1;
int main()
{
return INT_MIN % x;
}
不過,我可以找到在標準中沒有聲明,該代碼調用未定義或實現定義的行爲。據我所知,它需要返回0.這是一個gcc的錯誤,或者我錯過了標準所做的一些特殊例外嗎?
GCC產生浮動代碼,對於下面的代碼引發SIGFPE
:INT_MIN%-1是否會產生未定義的行爲?
#include <limits.h>
int x = -1;
int main()
{
return INT_MIN % x;
}
不過,我可以找到在標準中沒有聲明,該代碼調用未定義或實現定義的行爲。據我所知,它需要返回0.這是一個gcc的錯誤,或者我錯過了標準所做的一些特殊例外嗎?
您可能是對的,這可以被視爲實際標準中的錯誤。所述current draft解決了這個問題:
如果商A/B可表示, 表達式(A/B)* B + A%B應 等於一個;否則, 行爲a/b和a%b都未定義。
接受;這個答案解決了該委員會通過的錯誤和修正。對不起,花了這麼長時間。 – 2011-10-21 02:12:58
該語言是否可能包含在TC到C99中? – caf 2011-11-30 00:16:56
@caf,我的猜測是C99不會有TC,因爲C1x是爲了取代它。 – 2011-11-30 07:52:28
綜觀與gcc生成的彙編代碼(x被先前在組件定義爲-1):
movl x, %ecx
movl $-2147483648, %eax
movl %eax, %edx
sarl $31, %edx
idivl %ecx
的第一計算指令,sarl
,右移-2147483648
31比特。這導致-1
被放入%edx
。
Next idivl
被執行。這是一項簽署的操作。讓我引述的描述:
除以包含在所述合併%EDX的雙字的內容:通過在指定的寄存器或存儲器位置的值%eax中的寄存器。
所以-1:-2147483648/-1
是發生的部門。 -1:-2147483648
解釋爲一個雙字等於-2147483648
(在二補數機器上)。現在發生-2147483648/-1
,它返回2147483648
。繁榮!那是一個多於INT_MAX
。
關於爲什麼問題,這是一個gcc中的錯誤還是我缺少一些特殊的例外標準?
在這種C99標準是隱式的UB(§6.5.5/ 6):
... /運算的結果是與任何小數部分discarded.88代數商)如果商一/ b可表示,則表達式(a/b)* b + a%b應等於a。
INT_MIN/-1
無法表示,因此這是UB。
但是在C89中,%運算符是實現定義的,並且這是否是編譯器錯誤可以辯論。但問題在gcc列出:http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30484
有關* how * SIGFPE正在發生的信息是正確的。但我的擔憂是這是否正確。我從來沒有要求編譯器計算'INT_MIN/-1'(這會明顯導致UB溢出),只是爲了計算'INT_MIN%-1',並且在標準中我沒有發現後者調用UB的語句。仍然是一個翔實的答案。 – 2011-05-08 01:55:22
關於您引用的6.5.5/6:在前一段(5)中,它顯示「%操作符的結果是餘數」。第6段澄清說,當「餘數」可能不明確時,但「a」是「b」整倍數時「剩餘」不含糊;在這種情況下,唯一的餘數是0. – 2011-05-08 02:11:31
@R .:嗯,等待一秒,標準狀態爲「如果商a/b是可表示的」,INT_MIN%-1中不是這種情況。它沒有說明發生這種情況時應該發生什麼,因此它是UB。 – orlp 2011-05-08 02:19:11
感謝您提供有用的鏈接。至少它看起來像人們大多同意它是一個錯誤,但是「讓它在默認情況下破壞並且需要一個特殊的選項來修復它」的方法聽起來很荒謬...... – 2011-05-08 01:59:50
是否存在任何簡單的按位/算術表達式,如果'x!= - 1'則計算爲'x'並且如果'x == 1'計算爲'1'?如果是這樣,那麼編譯器可以在執行具有可變分母的'%'之前將其應用於分母,而不是使用相同的分母執行'/'。 – 2011-05-08 02:03:38
@R ..:「默認關閉,但是在標準符合模式下」聽起來沒錯,但這就是錯誤提示。 'gcc'不是一個合格的實現,也不是自稱的。 'gcc -std = c99'也不完全符合,但它確實是...... – 2011-05-08 09:03:46
具有負的操作數的模數操作的結果是由§6.5.5/ 6左實現定義在C89,和C99中定義:
&hellip;所述
/
操作符的結果是代數除去任何小數部分的商數。 88)如果商a/b
可表示,則表達(a/b)*b
+a%b
應等於a
。88)這通常被稱爲「截斷朝零」。
對於二進制補碼錶示,INT_MIN/-1
等於INT_MAX + 1
,所以它不能表示爲一個int
無包裝,我想執行選舉離開它爆炸。
然而,'/'運算符沒有出現在我的程序中。不管你如何用負操作數定義結果(「舍入」爲0或向下),-1均勻分割任何東西,因此數學上唯一可能的餘數爲零。 – 2011-05-08 01:56:43
@R ..:我只是引用了關於負操作數行爲的參考。 GCC實現它時計算失敗,所以如果你需要我用這麼多的話來說,它基本上是一個錯誤。 – 2011-05-08 02:59:08
@R ..換言之,'%'僅在定義了'/'時定義,並且由於'/'在這裏是未定義的,'%'也是未定義的,即使它可能不應該。 – 2011-05-08 08:09:36
同樣的問題在這裏提出的缺陷報告
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#614
不幸的是我沒有看到它在分辨率部分,它應該產生UB明確說明。該部門確實會生產UB,但對於%
運營商來說,這並不明顯。
請注意,全局變量是爲了防止gcc優化計算。 – 2011-05-08 01:22:12
因爲試圖獲得負數模的結果,您會期望什麼? – joce 2011-05-08 01:45:50
「當a或n爲負數時,這個幼稚的定義崩潰了,編程語言在這些數值的定義方式上有所不同。」 http://en.wikipedia.org/wiki/Modulo_operation – joce 2011-05-08 01:47:11