2017-02-14 9 views
0

マクロ関数への引数としてマクロ定数を渡そうとしているときに問題が発生しています。他のマクロを引数として使用してCマクロを呼び出す

は、次のコードを考えてみましょう -

#define ERROR 10 
#define MAIN "Main:" 

#define LOG(lvl,mod,fmt,...) \ 
    char msg[256] = {0}; \ 
    snprintf(msg, 256, "%s: %d: "fmt,mod,lvl,##__VA_ARGS__) 

int main() 
{ .... 
    LOG(ERROR, MAIN, "This is a log statement.\n"); // Doesn't compile 
    LOG(10, "Main:", "This is a log statement.\n"); // Compiles 
    .... 
} 

2番目のログ文がコンパイルされますが最初のログステートメントは、次のコンパイルエラーを生成 -

error: expected `)' before ‘;’ token 
error: expected primary-expression before ‘,’ token 
error: expected `;' before ‘)’ token 

なぜこの出来事はありますか?私は、ロギングレベルとモジュール定数のセットを定義し、LOG()マクロを呼び出す際にそれを使用したいと考えています。

+3

を、しかし、あなたの 'LOG'マクロはせずに、簡単な' if'文またはループ本体では動作しません明示的なブレイザー。ほとんどの人が 'do {...} while(0)'でマクロを囲んでいるのです。 –

+6

マクロは同じスコープ内に複数の 'msg'変数を宣言するため、壊れています。 – Droppy

+1

問題を解決する方法として、プリプロセッサを実行した後に停止して、マクロ展開がどのようなコードを作成するかを確認するようにコンパイラに指示します。 –

答えて

0

私が見ることができる二つの問題があります。

  1. はあなたが同じスコープ内で複数のmsgの変数を持つことになります。
  2. あなたはカンマがありません(@Ninetonedoによって指摘されています)。
  3. フォーマットされた文字列は何もしません。

ロギングレベルを受け入れ、マクロを使用して呼び出すのを短縮するグローバルlogger()関数を宣言することをお勧めします。

+0

カンマがない場合は問題ありません。文字列定数の連結が可能です。 @JohnnyMopp True。 –

+0

修正されました。 – Droppy

+0

おそらく実際のコードは 'msg'で何かをしますが、それは質問には関係しないので省略されています。 – rici

0

マクロの1つの問題は、C89では許可されていないコードブロック内の任意の場所に変数が宣言されていることです。ブロックの先頭にのみ変数を宣言できました。 C99コンパイラであっても、同じスコープ内で同じ名前の宣言を複数導入することはできないため、問題は解決されません。これは禁止されています。

あなたがこの問題を解決するためにdo/while(0) trickを使用することができます。

あなたの(現在の)問題とは無関係な
#define LOG(lvl,mod,fmt,...) do {\ 
    char msg[256] = {0}; \ 
    snprintf(msg, 256, "%s: %d: "fmt,mod,lvl,##__VA_ARGS__) \ 
} while(0) 
+0

OPが最初の2つの引数に対してマクロを使用していないときに、2番目の変種がコンパイルされる理由についても説明しません。 –

+1

@Someprogrammerdude最も可能性の高い理由は、OPのコードの前に、コンパイルしないコードがあります。そこには '.....'があります。コードを単独でコンパイルすると完全にコンパイルされます([demo] (http://ideone.com/F9TW7H))。 – dasblinkenlight

+0

私の実際のコードでは、このLOGマクロをコンストラクタ内から呼び出しています。これはコンストラクタの最初の命令です。 また、マクロは、呼び出される場所とは異なる.hファイルで定義されます。 .hファイルは上記の例と同じ正確な順序でマクロ定義を持っています。マクロ定義の順序付けはこれと何か関係がありますか? – siri

関連する問題