メインコンテンツ

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

CERT C: Rule PRE32-C

関数形式のマクロの呼び出しでプリプロセッサ命令を使用しない

説明

ルール定義

関数形式のマクロの呼び出しでプリプロセッサ命令を使用しないようにします。1

Polyspace 実装

ルール チェッカーは、"マクロ引数のプリプロセッサ命令" をチェックします。

すべて展開する

問題

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

たとえば、マクロ foo() などの関数の引数において #ifdef ステートメントが発生するとします。


#define foo(X) //...    
foo(
    #ifdef A
    "A"  
    #else
    "B"
    #endif
  );
チェッカーは、このような #ifdef ステートメントの使用で違反を報告します。マクロとして実装される可能性があるライブラリ関数の引数として #ifdef ステートメントが使用される場合にも、違反が報告されます。マクロとして実装される可能性があるライブラリ関数の例としては、assert()memcpy()、および printf() などがあります。

リスク

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

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

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

修正方法

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

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

#ifdef A
    foo("A");
#else
    foo("B")
#endif

例 - 関数形式のマクロの命令

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

#include <stdio.h>

#define print(A) printf(#A)

void func(void) {
    print(
#ifdef SW //Noncompliant
          "Message 1"
#else
          "Message 2"
#endif 
         );
}
修正 — マクロ外で命令を使用

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

#include <stdio.h>

#define print(A) printf(#A)

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

チェック情報

グループ: Rule 01.プリプロセッサ (PRE)

バージョン履歴

R2019a で導入


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.