請看下面一段簡單的代碼這是GCC(mingw)/ glibc bug - scanf是否有短褲?
int main()
{
short x = 0, y = 0;
scanf("%d", &x);
scanf("%d", &y);
printf("%d %d\n", x, y);
return 0;
}
如果你輸入4和5,這個程序,你會期望獲得4和5的輸出。在窗口(mingw)上使用GCC 4.6.2時,它產生0和5作爲輸出。所以我挖了一下。這是生成的彙編代碼
movw $0, 30(%esp)
movw $0, 28(%esp)
leal 30(%esp), %eax
movl %eax, 4(%esp)
movl $LC0, (%esp)
call _scanf
leal 28(%esp), %eax
movl %eax, 4(%esp)
movl $LC0, (%esp)
call _scanf
雖然我沒有做很多彙編編碼,但上面的代碼看起來不正確。它似乎暗示x被放置在esp的30個字節的偏移處,並且y被放置在esp的28個字節的偏移處,然後他們的地址被傳遞給scanf。因此,當x和y的地址以長整數(4字節地址)處理時,將發生以下情況: 第一次調用將字節[30,34)設置爲值0x00000004,第二次調用將設置字節[28,32)爲值0x00000005。但是,由於這是一個小端機器,我們將從30開始[0x04 0x00 0x00 0x00],然後從28開始[0x05 0x00 0x00 0x00]。這會導致字節編號30重置爲0.
I嘗試顛倒scanfs的順序,並且它工作(輸出確實是4和5),所以現在先填充較小的偏移量,然後填充較大的偏移量。
海灣合作委員會可能搞砸了這似乎是荒謬的。所以我嘗試了MSVC,它生成的程序集有一個明顯的區別。這些變量被放置在偏移量-4和-8處(即它們被認爲是4個字節長,儘管註釋表示2個字節)。下面是部分代碼:
_TEXT SEGMENT
_x$ = -8 ; size = 2
_y$ = -4 ; size = 2
_main PROC
push ebp
mov ebp, esp
sub esp, 8
xor eax, eax
mov WORD PTR _x$[ebp], ax
xor ecx, ecx
mov WORD PTR _y$[ebp], cx
lea edx, DWORD PTR _x$[ebp]
push edx
push OFFSET $SG2470
call _scanf
add esp, 8
lea eax, DWORD PTR _y$[ebp]
push eax
push OFFSET $SG2471
call _scanf
add esp, 8
我的問題是兩個部分:
- 我沒有在我手上了個人的Linux機器。這是海灣合作委員會的問題,還是隻是一個問題?
但是,更重要的是,
- 這是一個錯誤呢?編譯器如何判斷是否應該將「short」置於2字節偏移量或4字節偏移量?
「我沒有可用的個人Linux機器」 - 您可以通過在Windows機器上安裝VirtualBox,然後在VM中安裝Linux來解決此問題。 –