最近,我們在一些舊代碼中發現了奇怪的行爲。這段代碼已經工作了很長時間,但在某些平臺(XBox 360,PowerPC)上打開了,編譯器優化功能打開了最大值。通常,我會懷疑未定義的行爲。兼容編譯器可以中斷uint32_t - > int16_t - > int32_t轉換嗎?
代碼看起來大致是這樣的:
#include <stdint.h>
uint32_t sign_extend16(uint32_t val)
{
return (int32_t)(int16_t)val;
}
這是一個仿真的一部分,所以有問題的操作應該不會太陌生。通常情況下,我希望這隻考慮較低的16位,並將其擴展到32位。顯然,這是它長久以來的行爲。在x86_64,海灣合作委員會給了我這樣的結果:
0000000000000000 <sign_extend16>:
0: 0f bf c7 movswl %di,%eax
3: c3 retq
然而,從我能理解標準的,將一個無符號的簽署是沒有定義它應該是不可能的代表符號一與價值簽名類型。
那麼編譯器是否可以假設無符號值必須在[0, 32767]
的範圍內,因爲任何其他值都是未定義的?在這種情況下,投射到int16_t
而另一投到int32_t
什麼都不會做。在這種情況下,編譯器將代碼轉換爲簡單的移動是合法的嗎?
'(int16_t)val'的行爲永遠不會被定義。如果'val'可以表示爲'int16_t',則其行爲是明確定義的,否則行爲是實現定義的。 – 2012-02-09 23:25:01
@Maister你在x86_64上遇到的問題是什麼? 'movswl'指令不會簽署擴展名。當您通過32768值時,結果如何?在使用'gcc'的32位/ 64位系統上,返回值應該是'0xFFFF8000'。 – ouah 2012-02-09 23:58:17
我可能不夠清楚。在x86_64上的行爲是預期的。它不會像xbox 360上預期的那樣工作。 – Maister 2012-02-10 00:02:40