對於同樣的 C 語言代碼,為什麼 Mac OS X 上用 gcc 編譯運行的結果和其他系統不同?
以下代碼在 windows 和 Linux 上結果是5 4 3 2 ,而 Mac 上是2 3 4 5
#include "stdio.h"
int fun(void);
int main()
{
printf("%d %d %d %d
",fun(),fun(),fun(),fun());
return 0;
}int fun(void)
{
static int num = 1;
return ++num;
}
這不是未定義行為,而是一個未明確行為:
ISO/IEC 9899:1999
6.4.2.210 The order of evaluation of the function designator, the actual arguments, and subexpressions within the actual arguments is unspecified, but there is a sequence point before the actual call.副作用啊
Side Effects
c語言函數參數的求值順序是未定義的
標準委員會規定,大概是在兩個分號間同一變數只能更改一次,否則編譯器怎麼想就看編譯器心情了。
因為OS X 10.9 / Xcode 5 開始,系統里就不自帶gcc了,你用的那些命令(e.g. gcc g++)都是clang的別名。clang對:
printf("%d %d %d %d
",fun(),fun(),fun(),fun());
中4個fun()誰先執行與gcc實現不一樣。
在終端里輸入gcc -v,應該顯示的是這樣:(OS X 10.11.1 with Xcode 7.1)Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/c++/4.2.1
Apple LLVM version 7.0.0 (clang-700.1.76)
Target: x86_64-apple-darwin15.0.0
Thread model: posix
Bins-MacBook-Pro:~ binwang$ clang -v
Apple LLVM version 7.0.0 (clang-700.1.76)
Target: x86_64-apple-darwin15.0.0
Thread model: posix
Apple LLVM version 7.0.0 (clang-700.1.76)
Target: x86_64-apple-darwin15.0.0
Thread model: posix
可見他們都指向了一個編譯器clang。
更新:評論指出這是一個未明確的行為,見 @丁冬的答案===============================因為這是未定義行為,就跟i+++++i是一樣的
對於
printf("%d %d %d %d
",fun(),fun(),fun(),fun());
這句,語言標準並沒有規定這4個fun誰先執行,具體的實現跟編譯器有關。
所以答案就是,MAC上的實現不同。如果你想深入了解,可以搜索下「序列點」這個概念。當有序列點存在時,序列點前面的表達式必須求值完畢,並且副作用也已經發生, 才會計算序列點後面的表達式和其副作用。printf中逗號是一個序列點,但是序列點之間並沒有規定先後順序,因此四個fun可以以任意順序執行。推薦閱讀:
※GCC的參數-march=native是如何獲取cpu類型和指令集的?
※在使用coroutine+asio多線程框架的時候,如何維護連接池復用連接?
※Linux C++怎麼做框架的性能調優?