私はそれがあなたに与えると思います、マクロのユーザーはResult*
. 個人的には、あなたのやり方で行うか、(たとえば)void*
マクロ引数を本当に許可したい場合は、 *(Result*)(result) = callResult;
.
マクロの残りの部分がどのように見えるかによって、別の可能性があります。「いくつかの追加処理」はresultVar
まったく言及されていますか、それとも(*resultVar) = callResult;
条件付きの行ですか?その場合resultVar
、マクロが各引数を正確に1 回評価することを保証するために存在し、したがって、他の回数 (ゼロを含む) 評価した場合よりも関数呼び出しのように動作します。
したがって、次のようにループで呼び出すと、HANDLE_CALL(output++, *input++)
漠然と予測可能なことを行います。少なくとも、マクロの作成者が意図したとおりでoutput
ある場合はそうです。orResult*
のようなさまざまな引数タイプを許可する以外に、キャストが何を与えるかはまだわかりません。void*
char*
その余分なキャストがあるかどうかによって、別の違いが生じる可能性がある状況がいくつかあります. たとえば、次のことを考慮してください。
typedef double Result;
int foo() { return 1; }
int i;
HANDLE_CALL(&i, foo());
typedef double Result;
画面に表示されない場合、他の 3 行はほとんど無害に見えます。int に int を代入することの何が問題なのですか? int*
しかし、マクロが展開されると、 toをキャストすると悪いことが起こりますdouble*
。キャストでは、その悪いことは未定義の動作であり、おそらくdouble
よりも大きくint
、 のメモリをオーバーランしますi
。運が良ければ、「厳密なエイリアシング」に関するコンパイラの警告が表示されます。
キャストがなければできないdouble* resultVar = &i;
ため、その変更を加えた元のマクロは、厄介なことをする代わりに、エラーをキャッチしてコードを拒否します。のすべての値を正確に表すことができる場合、 を使用したバージョンは*result = callResult;
実際に機能します。IEEE double と53 ビット未満のどちらが可能です。double
int
int
おそらくResult
実際には構造体であり、上記のコードを実際に書く人は誰もいないでしょう。しかし、これは、なぜマクロが常にあなたが思っているよりも厄介なものになるかの例として役立つと思います.