2

列挙型の戻りコードと関数呼び出しを受け取る関数のようなマクロがあります。

#define HANDLE_CALL(result,call) \
    do { \
        Result callResult = call; \
        Result* resultVar = (Result*)result; \
        // some additional processing
        (*resultVar) = callResult; \
    } while(0)

派手なポインターのキャストResult*とそれに続く逆参照によって、何か得られるでしょうか? つまり、これを行う利点は次のとおりです。

callResult = call;
// additional processing
*result = callResult;

マクロは次のように使用されます。

Result result;
HANDLE_CALL(&result,some_function());

ところで、これは私のコードではなく、私はパワー C ユーザーではないので、これを行う背後に何らかのロジックがあるかどうかを理解しようとしています。

4

3 に答える 3

4

私はそれがあなたに与えると思います、マクロのユーザーは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 ビット未満のどちらが可能です。doubleintint

おそらくResult実際には構造体であり、上記のコードを実際に書く人は誰もいないでしょう。しかし、これは、なぜマクロが常にあなたが思っているよりも厄介なものになるかの例として役立つと思います.

于 2012-06-12T16:57:33.823 に答える
1

Result*Steve が言うように、キャストはマクロとは異なるものを渡すことができるようにすることです。しかし、キャストを行うべきではないと思います。これは危険ですが、初期化のみです。より良いだろう

#define HANDLE_CALL(result,call)         \
    do {                                 \
        Result callResult = (call);      \
        Result* resultVar = (result);    \
        /* some additional processing */ \
        (*resultVar) = callResult;       \
    } while(0)

resultこれにより、が と互換性のある代入であることが強制されるため、またはResult*のいずれかになります。(より大きな構造体へのポインター) を (タイプの最初のフィールド) などに強制キャストする他のすべての使用法は、火遊びとして役に立ちません。Result*void*Result

于 2012-06-12T20:28:40.240 に答える
0

それはすべて、人々がインスタンス化に渡す馬鹿げたものに依存します。本当にマクロが必要ですか - インライン関数の方が良いでしょう。

于 2012-06-12T16:55:56.677 に答える