【C/C++】 マクロと関数呼び出し

仕事でちょっとはまった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)は結局ループなしになるので、コンパイラの最適化でループ自体が削除されて無駄な命令が出力される事もない。(はず。コンパイラの最適化機能によるかね。)

という訳で、無事に解決しました。

Author: kan
初めてプログラムらしきものを作ったのは幼稚園の時。それから約40年経ち、現在はデジタル回路設計から信号処理、機械学習まで幅広い経験を活かしてシステムアーキテクトとして活動中。超並列処理、デジタル回路とソフトウェアのバランス設計が得意分野。 Linux/Mac/Windows使い。 C/C++を主要言語として、Unity、Qtなどのフレームワーク興味あり。UI/UXデザイン、STL拡張など。 音声処理、画像処理、技術コンサルは仕事でも請け負います。 一般ソフトウェア開発プロセス、医療機器ソフトウェア開発プロセス作成も進行中。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください