web-dev-qa-db-ja.com

Cマクロでの出力の使用と返却

エラーメッセージをキャッチして出力するコードをインストルメント化しようとしています。現在、私はこのようなマクロを使用しています:

_#define my_function(x) \
  switch(function(x)) { \
    case ERROR: \
      fprintf(stderr, "Error!\n"); \
      break; \
  }
_

通常、関数の出力をキャプチャすることはありません。これは正常に機能します。しかし、function()の戻り値も必要とするケースをいくつか見つけました。次のようなことを試しましたが、構文エラーになります。

_#define my_function(x) \
  do { \
    int __err = function(x); \
    switch(__err) { \
      case ERROR: \
        fprintf(stderr, "Error!\n"); \
        break; \
    } \
    __err; \
  } while(0)
_

関数の戻り値を保持するグローバル変数を宣言することもできますが、見栄えが悪く、プログラムがマルチスレッド化されているため、問題が発生する可能性があります。より良い解決策があることを願っています。

16
Michael Mior

これは比較的複雑なコードであり、マクロで使用する理由はあまりありません。本当にヘッダーファイルに配置する場合は、inline(C99)またはstatic(C89)またはその両方にします。妥当なコンパイラがあれば、マクロと同じ効率になります。

9
Jens Gustedt

GCCには ステートメント式 と呼ばれる機能があります

したがって、次のようなマクロを定義すると

#define FOO(A) ({int retval; retval = do_something(A); retval;})

それからあなたはそれを次のように使うことができます

foo = FOO(bar);
54
qrdl

非常に遅い返事。しかし、それでもなお。インライン関数の方が優れていることに同意しますが、MACROは、インライン関数では得られないかなりの印刷の楽しみを提供します。 @qrdlに同意します。ステートメントを少し再構成すれば、ステートメント式を実際に使用できます。これがマクロでどのように機能するかです-

#define my_function(x, y) ({ \
  int __err = 0; \
  do { \
    __err = function(x, y); \
    switch(__err) { \
      case ERROR: \
        fprintf(stderr, "Error!\n"); \
        break; \
    } \
  } while(0); \
  __err; \
})
5
linuxmonk

これは編集です...

  1. 中括弧が必要だと思います。 do..whileキーワードは不要
  2. バックスラッシュが各行の最後の文字であることを確認してください(後にスペースを入れないでください)。
  3. マクロからエラー値を取得する必要がある場合は、パラメーターを追加するだけです。

そのようです:

 #define my_function(x, out) \
      { \
        int __err = function(x); \
        switch(__err) { \
          case ERROR: \
            fprintf(stderr, "Error!\n"); \
            break; \
        } \
        __err; \
        (*(out)) = _err; \
      }

参照渡しのCパラダイムを保持するには、次のようにmy_functionを呼び出す必要があります。

int output_err;

my_function(num, &output_err);

このように、後でmy_functionを実際の関数にする場合は、呼び出し参照を変更する必要はありません。

ところで、qrdlの「ステートメント式」もそれを行う良い方法です。

2
hopia