2013-03-15 83 views
4
#include<stdio.h> 
#define CUBE(x) (x*x*x) 

int main() 
{ 
int a, b=3; 
a = CUBE(++b); 
printf("%d, %d\n", a, b); 
return 0; 
} 

該代碼返回值a=150b=6。請解釋一下。解釋這個C程序的輸出?

我認爲,當它執行的a值將被計算爲a=4*5*6=120但根據編譯器是不正確的,所以請解釋邏輯....

+0

體現在哪裏?如果我使用gcc 4.2.1,我得到結果:a = 120,b = 6 – 2013-03-15 17:50:17

+1

@Magnus:任何結果都是可能的。你可以得到'a = 120,b = 6'或者你可以得到'土豆'。這是未定義的行爲。 – 2013-03-15 18:02:01

回答

9

有沒有邏輯,這是不確定的行爲,因爲

++b * ++b * ++b; 

修改並讀取3次,沒有交錯序列點。

獎勵:如果您嘗試CUBE(1+2),您會看到另一個奇怪的行爲。

5

除了什麼Luchian格里戈裏說(這也解釋了爲什麼你看到這個怪異的行爲),你應該注意到這個宏可怕:它可能會導致微妙,很難追蹤下的錯誤,尤其是在與一個叫語句有副作用(如++b),因爲這會導致語句執行多次。

您應該從這次發現三條東西:

  1. 決不參考宏參數比宏一次。雖然這條規則有例外,但您應該將其視爲絕對的。

  2. 嘗試避免在可能的情況下調用帶有包含副作用的語句的宏。

  3. 嘗試到避免函數式的宏如果可能的話。改用內聯函數。

2

它的undefined behavior在一個序列中多次改變相同的變量。而且因爲這個原因,你將得到不同的編譯器爲你的代碼的不同結果。

通過機會我也得到了同樣的結果a = 150 and b = 6與我的編譯器。

gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) 

您的宏表達a = CUBE(++b);大片如

a = ++b * ++b * ++b; 

而且bfull expression.年底前改變更多然後一次。但我的編譯器如何在低級別轉換此表達式(可能是您的編譯器做類似的操作,您可以嘗試使用相同的技術)。爲此,我使用-S選項編譯了源代碼C,並獲得了彙編代碼。

gcc x.c -S 

您將獲得x.s文件。

我顯示部分有用的彙編代碼(閱讀評論

因爲你想知道如何做150輸出,這就是爲什麼我加入我的答案

movq %rsp, %rbp 
.cfi_def_cfa_register 6 
subq $16, %rsp 
movl $3, -8(%rbp) // b = 3 

addl $1, -8(%rbp) // b = 4 
addl $1, -8(%rbp) // b = 5 

movl -8(%rbp), %eax // eax = b 
imull -8(%rbp), %eax // 5*5 = 25 

addl $1, -8(%rbp) // 6 `b` become 6 and 

imull -8(%rbp), %eax // 6 * 25 = 150 
movl %eax, -4(%rbp) // 150 assign to `a` become 150 

movl $.LC0, %eax  // printf function stuff... 
movl -8(%rbp), %edx 
movl -4(%rbp), %ecx 
movl %ecx, %esi 
movq %rax, %rdi 

在檢查這彙編代碼我可以理解它評估表達式,如 a = 5 * 5 * 6因此a變成150,並在三個增量後b變爲6

雖然不同的編譯器產生不同的結果,但我認爲,150駕駛室只評估了此序列b=3和您使用什麼編譯您在5*5*6