C言語には仕様が明確にされていない部分がある
先日来より、コンパイラ依存についてしつこく書いてきました。
実は、C言語の仕様には明確にされていない部分があります。
関数引数の評価順序
これがまさに「C言語の仕様として明確にされていない部分」にあたります。
「関数引数の評価順序」
や、あるいは英語でも
「order of evaluation function parameters」
で検索するといくつもヒットします。
曰く。
規定されていない
未規定
unspecified
等々
これまで、
clang が正しいのか
VS、gcc が正しいのか
という視点で考えてきたのですけど、結論としては
みんな正しい
と、こんなことになってしまうのです。
clang は第1引数から順に評価した
VS、gcc は第3引数から評価した
そういうことでしかない。
・・・のか?
と、ここまで書いてきてまたまた気になってしまうわけです。
VS、gcc は本当に第3引数から評価しているのか
確かに、第3引数の計算結果が第1引数、第2引数に反映されているんですけど、
第3引数から評価した
というのではなく、
まず第1引数から順に評価して、
その後に第1引数からプッシュした
ということではないか。
アセンブラを見てると、そんな風に見えてきます。
この場合、それぞれの引数を2回走査するということになるんだけども。
引数の並びを逆にするとどうなるのか
引数で関数を呼び出すとどうなるのか
あー。
どこまで行くんやろ。
ちなみに、C言語で明確にされていない仕様というのは、おそらく他にもあります。
できれば、
1行、1文、1演算子、1関数呼出し
くらいにしておく方がいい。
もちろん、特定のコンパイラだけ動作保証できればいいという考え方もあります。ですが、C言語で書いたソースコードというのは意外に寿命が長い。CPUが変更になるということは少なからずあります。そうなるとOSが変わる。コンパイラも変わる。
いっそコンパイルエラーにでもなればいいのですけど、コンパイルは通る。動作もそれなりに動く。でも値が違う。そういうことになりかねません。
あるいは、そんな未来のことを考える必要もないかもしれません。C言語という高水準言語を使うメリットはプラットホームに依存しないということにあります。今回のように、Android、Windowsの両方を対応したいと思うことも多いでしょう。ところが、Androidでは動くけど、Windowsでは動かない。そういう状況に出くわすかもしれません。
昔は少しでも速く動作できるプログラムというものが求められました。ハードウェアがまだまだ成長期で、プログラムの一工夫で処理速度が大きく変わるというようなこともままありました。現在でももちろん処理の速さを求められるプログラムはあります。ですが、一般的にはそう多くはありません。画面の入出力にも時間がかかるので、演算の処理速度が目立たない。それよりもむしろ、どこでも使える汎用的なプログラムが求められる時代のように思います。
いずれにしましても、プログラムするときには少し気にしてみてください。
コンパイラに依存するコードを書いていないかどうかを。
以下、過去の記事です。
参考までに。