仕事でちょっとはまったC言語の問題。
マルチプラットフォームでビルドしてたんやけど、謎なエラーが表示されててん。
コンパイルしたコードは以下の通り。
if ( condition ) test_func( … );
else test_func( … );
エラー表示されたメッセージは
error: expected primary-expression before ‘else’
ってな感じでしたわ。
なんで else がパースされへんのか?と思って色々調査。
if ( condition ) test_func( … )
else test_func( … );
とすると、コンパイルできました。
これはおかしい。
結局、よく調べてみると test_func というのは関数やなくて、マクロ関数で定義されていました。
#define test_func( … ) { hogehoge(); fugafuga; … }
こんな感じ。そのためプリプロで展開すると
if ( condition ) { hogehoge(); fugafuga(); … };
else { hogehoge(); fugafuga(); … };
といった具合になって、1行目の末尾のセミコロンが悪さをしていました。
今回の問題は実はもうちょっと複雑で、片方のプラットフォームでは test_func は外部関数、もう片方のプラットフォームではマクロ関数で定義されていました。そのため、同じソースコードなのにプラットフォーム毎にエラーが起きたり起きなかったりと不可解な挙動をしたわけです。で、問題は回避方法。片方がマクロ関数である限り、セミコロンをつける事はできひんけど、外部関数の呼び出しでエラーになっていまう。逆もしかり。一番手軽な修正方法は中括弧をつける事かね。
if ( condition ) { test_func( … ); }
else { test_func( … ); }
こんな感じにすればマクロ関数でも外部関数でも動作する。
せやけど、シングルステートメントの if〜else 文が書かれへんよなぁ。
色々悩んでいたんやけど、ふと昔見たことがあるテクニックを思い出しました。
#define test_func( … ) do { hogehoge(); fugafuga(); } while(0)
って定義すれば良いんやった。[E:wink]
最後にセミコロンはつけへんように注意。
このマクロ関数はステートメントの末尾にセミコロンを持つ普通の関数のように扱えるわけや。
while(0)は結局ループなしになるので、コンパイラの最適化でループ自体が削除されて無駄な命令が出力される事もない。(はず。コンパイラの最適化機能によるかね。)
という訳で、無事に解決しました。