メインコンテンツ

マクロ引数のプリプロセッサ命令

関数形式のマクロの引数で使用されるプリプロセッサ命令

説明

この欠陥は、関数形式のマクロまたは関数形式のマクロとして実装される可能性がある関数の引数でプリプロセッサ命令を使用した場合に発生します。

たとえば、関数 memcpy の引数において #ifdef ステートメントが発生するとします。関数 memcpy はマクロとして実装される場合があります。

memcpy(dest, src,
    #ifdef PLATFORM1
      12
    #else
      24
    #endif
  );
チェッカーは、同じくマクロとして実装される可能性のある printf および assert における同様の使用にフラグを設定します。

リスク

前処理中、関数形式のマクロ呼び出しはマクロ本体に置き換えられ、そのパラメーターはマクロ呼び出しの引数に置き換えられます (引数の置換)。マクロ min() が次のように定義されているとします。

#define min(X, Y)  ((X) < (Y) ? (X) : (Y))
min(1,2) を呼び出すと、その本体 ((X) < (Y) ? (X) : (Y)) に置き換えられます。XY は 1 と 2 に置き換えられます。

C11 規格 (節 6.10.3) によると、関数形式のマクロ自体の引数のリストにプリプロセッサ命令がある場合、前処理中における引数の置換は未定義になります。

修正方法

引数の置換が明確な方法で発生するように、関数形式のマクロの外でプリプロセッサ命令を使用します。

たとえば、#ifdef 命令に基づくさまざまな引数を使用して memcpy を実行するには、#ifdef 命令分岐内で memcpy を複数回呼び出します。

#ifdef PLATFORM1
    memcpy(dest, src, 12);
#else
    memcpy(dest, src, 24);
#endif

すべて展開する

#include <stdio.h>

#define print(A) printf(#A)

void func(void) {
    print(
#ifdef SW
          "Message 1"
#else
          "Message 2"
#endif
         );
}

この例では、プリプロセッサ命令 #ifdef および #endif が、関数形式のマクロ print() の引数において発生します。

修正 — マクロ外で命令を使用

1 つの修正方法として、関数形式のマクロを #ifdef 命令の分岐内で複数回使用します。

#include <stdio.h>

#define print(A) printf(#A)

void func(void) {
#ifdef SW
        print("Message 1");
#else  
        print("Message 2");
#endif 
}

結果情報

グループ: プログラミング
言語: C | C++
既定値: 手書きコードはオン、生成コードはオフ
コマンド ライン構文: PRE_DIRECTIVE_MACRO_ARG
影響度: Low

バージョン履歴

R2018a で導入