1

次のようにマクロを定義したいと思います。

#define MYCheckedCall(stmnt) do {         \
    status_t status = (stmnt);            \
    if (MYFail(status)) {                 \
        MYLog("Statement failed!");       \
    }                                     \
} while (0)

そして、数回の呼び出しごとにアプリケーション全体でそれを使用します。どこでもコードを繰り返すのと比較して、これのパフォーマンス特性は何ですか?(つまり、status_tを1回だけ定義し、追加の{}スコープは定義しません)

注意すべき点のカップル:

  • これにより、スタックにフレームが追加され(変数を格納するためstatus_t)、パフォーマンスに対する私の好奇心が高まります。
  • status_tはtypedef int status_tまたは類似のものです。
  • これは、ライブラリ全体のコードの半分のように使用されます。

これは少し時期尚早の最適化であることを私は知っていますが、それは些細な決定であるはずだったので、それにもかかわらずそれについて知りたいですか?


現在のコードの例(マクロなし):

status_t status = 0;
status = call1();
if (MYFail(status)) MYLog("call1 failed!");

status = call2();
if (MYFail(status)) MYLog("call2 failed!");

マクロでどのようにしたいかの例:

MYCheckedCall( call1() );
MYCheckedCall( call2() );

私がC初心者であり、この種の機能を実装するためのより良いパターン/方法がある場合は、それについても知りたいと思います。

Mac OSX10.7でclang/llvm-gccを使用しています。

4

3 に答える 3

6

整数型であると仮定すると、レジスタに格納されるオーバーヘッド、または最悪の場合は毎回同じスタックスロットに格納されるstatus_tオーバーヘッドはゼロになると思います。status関数のエントリに必要な最大スタックスペースを予約し、同じスタックスロットを再利用できるため、コンパイラはスタックを調整する必要はありません。

いつものように、興味がある場合は、アセンブラの出力をチェックして、これがコンパイラの機能であることを確認する必要があります。

于 2012-07-10T12:16:01.723 に答える
6

時期尚早の最適化は心配する必要はありません。さらに、コードサイズは通常、パフォーマンスの信頼できる指標ではありません(100万回繰り返される3行のループは、1000の命令を持つプログラムよりも約1000倍長くかかると考えてください)。したがって、後で最適化について考えてください。

あなたの場合、プリプロセッサがすべてのマクロ呼び出しをマクロ用に作成したコードに置き換えるため、違いはないと思います。したがって、基本的に同じコードについて話していることになります(この定義を確認してください)。

于 2012-07-10T12:17:19.623 に答える
1

この特定の構成のパフォーマンスについてはまったく心配しません。後でプロファイリングによってボトルネックであることが判明した場合は、それを最適化できます。そして、マクロの代わりに、関数を使用します。マクロを拡張したい場合、マクロはすぐにメンテナンスの悪夢になる可能性があります。

void MYCheckedCall (status_t status, const char *fail_message)
{
    if (MYFail(status))
    {
        MYLog(fail_message);
    }
}

MYCheckedCall(call1(), "call1 failed!");
MYCheckedCall(call2(), "call2 failed!");

関数/マクロが実際に行うことであるため、名前をMYStatusCheckに変更することもできます。

于 2012-07-10T12:49:13.940 に答える