對於同樣的 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.2

10 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

clang -v,就是這樣了:

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++怎麼做框架的性能調優?

TAG:Linux | C編程語言 | CC | GCC | 編譯器 |