inline void __DUMMY_TRACE__(...) {}
#define TRACE 1 ? ((void) 0) : __DUMMY_TRACE__
この2行の記述がビルド時に有効になるのですが、
なぜいきなり、
#define TRACE ((void) 0)
と記述しないのでしょうか?
もし、#define TRACE __DUMMY_TRACE__
と言う記述であれば、
inline void __DUMMY_TRACE__(...) {}
が意味を持ってくることはわかるのですが。。。
http://www.kab-studio.biz/Programing/PragmaTwice/Main/118.html
#pragma twice 118
ちょっと気になったので.
(void)0 はアドレス0 へのアクセスにはなりません.関数へのポインタでもありません.
(void)0 は,C言語で 何もしない と記述する際の常套手段です.詳細は上記URLをご覧下さい.
http://www.hey-to.net/ML-archive/vcppML/2000/msg01451.html
[vcpp 00038073] (void)0 $B4X?t%]%$%s%?$KIU$$$F(B.
結局は処理系依存の為の記述ではないでしょうか?
TRACE(”Hoge”);
というコード記述があった場合、M$社の定義では
1 ? ((void) 0) : __DUMMY_TRACE__(”Hoge”);
と解釈され、akunakiさんの言われている定義では
((void) 0)(”Hoge”);
となります。VC++では「((void) 0)(”Hoge”);」という記述は通常の
「(void)0」(NULLポインタ関数呼び出し)として解釈されるようですが
BC(BorlandC++)など他のコンパイラではエラーが発生するものもあるようです。
正直僕自身も勉強不足なのであまり分かっておりません。(^-^;)
此方のスレッドでも議論されております、参考までに。
TRACE(my_func(i))
なんて書いたときに、
#define TRACE ((void) 0)
だと、
((void) 0)(my_func(i))
になって my_func(i)が実行されちゃいますが、
inline void __DUMMY_TRACE__(...) {}
#define TRACE 1 ? ((void) 0) : __DUMMY_TRACE__
だと、
1 ? ((void) 0) : __DUMMY_TRACE(my_func(i))
となって、my_func(i)が呼び出されません。
#define TRACE __DUMMY_TRACE__
も
__DUMMY_TRACE__(my_func(i))
となって同様です。
TRACEの引数に書いた部分が評価されちゃうか否かの違いですね。
inline void __DUMMY_TRACE__(...) {}
#define TRACE 1 ? ((void) 0) : __DUMMY_TRACE__
だと、
まず、2行目の置き換えで、
1 ? ((void) 0) : __DUMMY_TRACE(my_func(i))
となり、次に1行目の置き換えで
だたの、
{}
になるから、本当に何も無くなるということですね?
そうすると、
inline void __DUMMY_TRACE__(...) {}
#define TRACE __DUMMY_TRACE__
では、だめなのでしょうか?
http://www.techmatrix.co.jp/products/quality/insure/feature/erro...
Insure++ (C C++対応自動エラー検出ツール) : 検出されるエラー一覧
>#define TRACE ((void) 0)
>と記述しないのでしょうか?
これがどんな環境でも成立するためには、アドレス0での呼び出し結果がどんな環境でも一致している必要があります。
が、特定のアドレスの呼び出しは、環境依存、OS依存になりますから、一般的には使えません。
例えば、仮想記憶を持たないOS,環境では物理アドレス0の呼び出しになり、
これが無効処理などでなく特別な処理になる場合もあり、これが別の意味(TRACE)に固定されてしまうと困ることになります。
特定のOS,環境化でならともかく、一般的には使ってはいけない定義でしょう。
URLはNULLの関数呼び出しでエラーになる例です。
本当の物理アドレス0へのアクセスもあり得ると言うことですね。ご教授有り難う御座います。
The GNU Operating system - the GNU project - Free Software Foundation - Free as in Freedom - GNU/Linux
マクロとinline関数、プリプロセッサとコンパイラの最適化で混乱があるようです。
>まず、2行目の置き換えで、
>1 ? ((void) 0) : __DUMMY_TRACE(my_func(i))
>となり、
はマクロのプリプロセッサによる展開で、ここまではOKですが、
>次に1行目の置き換えで
>だたの、
>{}
>になるから、本当に何も無くなるということですね?
inline関数はマクロではありませんから、ここは正しくありません。あくまでもcのソース上は関数呼び出しです。
ここで、3項演算子の最初の項が必ず真になることから__DUMMY_TRACE__ を呼び出す方は実行されることがない、つまり引数の処理 myfunc(i)は実行されることがない、ということになります。
コンパイラの最適化によっては、結果の実行ファイルではそのように空になるかもしれませんが、それはまた別の話です。
ですから、
>inline void __DUMMY_TRACE__(...) {}
>#define TRACE __DUMMY_TRACE__
ですと、
TRACE(myfunc(i))
は
__DUMMY_TRACE__(myfunc(i))
です。
cのソース上はmyfunc(i)の結果を引数に関数を呼び出していることになりますから、__DUMMY_TRACE__の実装の中身が空だろうとどうだろうと関係なくて myfunc(i) は必ず実行されなければなりません。ということで、TRACEを無効にしたはずなのに無用なmyfunc(i)の実行がされてまずいことになります。
3項演算子の最適化と言うことがよくわかりました。有り難う御座いました。
昔の名残とのことですが、他の情報ソースでも同様なのでしょうか?(ちょっと納得がいかないです。)