メインコンテンツ

MISRA C:2012 Dir 4.9

A function should be used in preference to a function-like macro where they are interchangeable

説明

命令の定義

A function should be used in preference to a function-like macro where they are interchangeable 1 .

根拠

可能な場合には、マクロの代わりに関数を使用します。関数は引数タイプのチェックと引数の評価を 1 回のみ行い、複数の潜在的な二次的影響を含む問題を回避します。

Polyspace 実装

コード内でマクロが少なくとも 1 回使用され、そのマクロが関数によって置換される可能性がある場合、Polyspace® はこのルールに対する違反を報告します。Polyspace は、以下のいずれかの条件が当てはまる場合、関数によってマクロが置換されることはないと仮定します。

  • マクロが連結を使用して、関数を定義するか、関数の呼び出しを生成する。たとえば、マクロ MYFUNC では、マクロ パラメーター name を使用して、新しい関数をインラインで作成できるようになっています。Polyspace は、関数によって MyFunc が置換されることはないと仮定し、違反を報告しません。

    //Noncompliant
    #define DH(x) do { printf("using variable = %d\n", x);} while(0)
    //Compliant
    #define MYFUNC(name) void myFunc_##name(){printf("call to function\n");}
    マクロ DH が、関数を定義していないか、関数の呼び出しを生成しない。Polyspace は、このマクロは関数によって置換される可能性があると仮定し、違反を報告します。

  • マクロがキーワード returngotolabel を使用して制御フローを中断する。キーワード break の使用、あるいは switch ブロックまたはループ外部でのキーワード continue の使用も、関数によってマクロが置換されることはないことを示します。たとえば、マクロ RETURN_NUM は値を返します。マクロ CASES に、switch または loop ステートメント外部の break 識別子が含まれている。Polyspace は、これらのマクロが関数によって置換されることはないと仮定します。

    #define RETURN_NUM(x) do { \
        an_uint32 += x; \
        return 10; \
    } while(0)
    #define CASES_(x) \
        case 0: \
            printf("0\n"); \
            break; \
        case 1: \
            printf("1\n"); \
            break; \
        default: \
            printf("default\n");

  • マクロが、そのマクロ内で使用されない変数を少なくとも 1 つ宣言している。たとえば、マクロ DECLARE_AND_INITIALIZE_VAR は 3 つの整数を宣言して初期化します。Polyspace は、このマクロが関数によって置換されることはないと仮定します。

    #define DECLARE_AND_INITIALIZE_VAR(x, y, z) \
      int8_t x = 1; \
      int8_t y = x + 1; \
      int8_t z = y + 1;

  • マクロが次のシンボルおよびキーワードのいずれかを使用している: #__LINE____FILE___Generic

  • 少なくとも 1 つのマクロのパラメーターが、マクロの本体で型として使用されている。たとえば、マクロ DECLARATION および CONVERSION のそれぞれが、本体内でそのいずれかのパラメーターを型として使用しています。Polyspace は、これらのマクロが関数によって置換されることはないと仮定します。

    #define DECLARATION(x, T) do { \
        const T y = x; \
        an_uint32 += y; \
    } while(0)
        
    #define CONVERSION(x, T) ((T) (x)) 

  • 少なくとも 1 つのマクロのパラメーターが演算子または式である。たとえば、マクロ OPERATION は演算子を入力として取ります。マクロ STATEMENT は式を入力として取ります。Polyspace は、これらのマクロが関数によって置換されることはないと仮定します。

    #define OPERATION(x, y, op) ((x) op (y))
    #define STATEMENT(x, action) \
        if (!x) action

  • マクロがグローバル変数または static 変数を初期化するために使用される。この目的での関数の呼び出しは許可されません。

トラブルシューティング

ルール違反を想定していてもその違反が表示されない場合、コーディング規約違反が想定どおりに表示されない理由の診断を参照します。

すべて展開する

この例では、関数形式のマクロ MAX は引数を複数回評価します。このマクロを呼び出した後で、x の値は 6、y の値は 12 になります。これは予期されていないため、Polyspace はこの関数形式のマクロに対して違反を報告します。

#include <stdio.h>

#define MAX(a, b) ((a) > (b) ? (a) : (b))  //Noncompliant

int main() {
	int x = 5;
	int y = 10;
	int max = MAX(x++, y++);

	printf("max: %d\n", max);
	printf("x: %d\n", x);
	printf("y: %d\n", y);
	return 0;
}

チェック情報

グループ: Code design
カテゴリ: 推奨
AGC カテゴリ: 推奨

バージョン履歴

R2014b で導入

すべて展開する


1 All MISRA coding rules and directives are © Copyright The MISRA Consortium Limited 2021.

The MISRA coding standards referenced in the Polyspace Bug Finder™ documentation are from the following MISRA standards:

  • MISRA C:2004

  • MISRA C:2012

  • MISRA C:2023

  • MISRA C++:2008

  • MISRA C++:2023

MISRA and MISRA C are registered trademarks of The MISRA Consortium Limited 2021.