C99未定義の動作を試すとこうなる
このコードはC99としてコンパイルすることが出来る。(注: 最近のgccでは問題の式について警告を発します)
#include <stdio.h> int print(int num, int args[]) { int i; for(i = 0; i < num; ++i) { printf("%d", args[i]); } return 1; } int main() { int a = 2; return print(1,(int[]){print(1, (int[]){print(2, (int[]){++a, print(1, (int[]){a + print(1, (int[]){print(2, (int[]){++a, ++a})})})})})}) && print(1, (int[]){a}); }
しかし、C99規格では
- 初期化子の並びの副作用実行順序は未規定
とされているため、このコードの実行結果は未定義とされる。関数や完結式(ある式の部分式でない式)が副作用完了点とされているので、returnの式中にある前置インクリメントの式たちは未定義の動作とはならない、はず。
未定義の動作を2つの異なるコンパイラで体験してみよう。
一つ目はgcc、言わずと知れたメジャーなCコンパイラの一つだ。大体のLinux環境や*BSD環境にインストールされている。
コンパイル&実行すると、
$ gcc --version gcc (GCC) 4.2.1 20070719 Copyright (C) 2007 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ gcc -std=c99 test.c && ./a.out 551651115
こうなる。
二つ目はPCC、30年ほどの歴史を持つ老舗のCコンパイラーだ。30年ぶりにC99対応をひっさげて1.0.0がでたとか、OpenBSDがソースツリーに取り込んだという話を聞いたことがあるけど、その後の報道がない。
コンパイル&実行すると、
$ pcc --version pcc 1.1.0.DEVEL 20111207 for i386-unknown-openbsd5.0 $ pcc -std=c99 test.c && ./a.out 341551115
gccと1、2、4番目の出力が異なる。
それぞれコンパイラが生成した実行順序について考察してみるとおもしろいだろう。
- 元ネタ(written by [twitter
- @fadis_]):http://ideone.com/B3dob