#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=150
和b=6
。請解釋一下。解釋這個C程序的輸出?
我認爲,當它執行的a
值將被計算爲a=4*5*6=120
但根據編譯器是不正確的,所以請解釋邏輯....
#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=150
和b=6
。請解釋一下。解釋這個C程序的輸出?
我認爲,當它執行的a
值將被計算爲a=4*5*6=120
但根據編譯器是不正確的,所以請解釋邏輯....
有沒有邏輯,這是不確定的行爲,因爲
++b * ++b * ++b;
修改並讀取3次,沒有交錯序列點。
獎勵:如果您嘗試CUBE(1+2)
,您會看到另一個奇怪的行爲。
除了什麼Luchian格里戈裏說(這也解釋了爲什麼你看到這個怪異的行爲),你應該注意到這個宏可怕:它可能會導致微妙,很難追蹤下的錯誤,尤其是在與一個叫語句有副作用(如++b
),因爲這會導致語句執行多次。
您應該從這次發現三條東西:
決不參考宏參數比宏一次。雖然這條規則有例外,但您應該將其視爲絕對的。
嘗試避免在可能的情況下調用帶有包含副作用的語句的宏。
嘗試到避免函數式的宏如果可能的話。改用內聯函數。
它的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;
而且b
是full 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
體現在哪裏?如果我使用gcc 4.2.1,我得到結果:a = 120,b = 6 – 2013-03-15 17:50:17
@Magnus:任何結果都是可能的。你可以得到'a = 120,b = 6'或者你可以得到'土豆'。這是未定義的行爲。 – 2013-03-15 18:02:01