#include <stdio.h> int f(int, int, int) { return 0; } int main() { return f(printf("a"), printf("b"), printf("c")); }
这是今天晚上遇到的腾讯在线笔试题目,问题是 “代码结果是什么?”这道题目结果是 cba 吗?为什么?
业精于勤,荒于嬉;行成于思,毁于随。
拿這種未定義行為出題的騰訊也是夠了。建議回答「這個結果是不是cba並不重要,重要的是日常工作中不要寫出這樣的程式碼-- 盡量不要一行程式碼中寫太多函數調用,除非是鍊式調用;對於有副作用的函數調用那必須要分開成多行來寫。
大部分的呼叫約定是從右向左入棧,即最右邊的參數最先入棧,比如f(a, b, c),那麼最先入棧的就c,其次是b,最後是a 。具體到那你這裡,首先入棧的是printf("c")的回傳值,那麼這裡就會先對printf("c")進行一個呼叫。因此這段程式碼的函數呼叫順序最終為printf("c"), printf("b"),printf("a"),f(1,1,1)。所以程式碼結果是cba。
C語言預設的Calling Convention是cdecl,也就是從右向左壓棧。但是參數表求值順序是未定義行為,函數參數表中的逗號並不是序列點。 debug版的msvc和x86的gcc似乎都是從右到左求值的,但是據我所知Sparc上好像就是反過來的。至於優化過的release版則更無法確定了。
考得就是參數入棧方向,答案就是cba,上面解釋的很好了。 想說的是,我記得騰訊筆試題前面是有針對考題的保密協議的,追求技術問題的答案並沒有錯,但題主也要遵循你同意過的協議。
傳參順序不等於求值順序,也就是說這題目應該是錯的,但是如果選的話建議選cba,因為調用約定多為從右向左穿參,出題者很可能誤解為求值順序也是如此
但是main函數裡面回傳的是f函數,而f函數的回傳值是0,那麼main函數回傳值為什麼不是0呢?
拿這種未定義行為出題的騰訊也是夠了。建議回答「這個結果是不是cba並不重要,重要的是日常工作中不要寫出這樣的程式碼-- 盡量不要一行程式碼中寫太多函數調用,除非是鍊式調用;對於有副作用的函數調用那必須要分開成多行來寫。
大部分的呼叫約定是從右向左入棧,即最右邊的參數最先入棧,比如f(a, b, c),那麼最先入棧的就c,其次是b,最後是a 。具體到那你這裡,首先入棧的是printf("c")的回傳值,那麼這裡就會先對printf("c")進行一個呼叫。因此這段程式碼的函數呼叫順序最終為printf("c"), printf("b"),printf("a"),f(1,1,1)。所以程式碼結果是cba。
C語言預設的Calling Convention是cdecl,也就是從右向左壓棧。但是參數表求值順序是未定義行為,函數參數表中的逗號並不是序列點。 debug版的msvc和x86的gcc似乎都是從右到左求值的,但是據我所知Sparc上好像就是反過來的。至於優化過的release版則更無法確定了。
考得就是參數入棧方向,答案就是cba,上面解釋的很好了。
想說的是,我記得騰訊筆試題前面是有針對考題的保密協議的,追求技術問題的答案並沒有錯,但題主也要遵循你同意過的協議。
傳參順序不等於求值順序,也就是說這題目應該是錯的,但是如果選的話建議選cba,因為調用約定多為從右向左穿參,出題者很可能誤解為求值順序也是如此
但是main函數裡面回傳的是f函數,而f函數的回傳值是0,那麼main函數回傳值為什麼不是0呢?