メインコンテンツ

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

オブジェクトとして使用される事前定義されたマクロ

asserterrno などの標準ライブラリのマクロをオブジェクトとして使用する

説明

この欠陥は、基になるオブジェクトの存在が必要な方法で、特定の識別子を使用した場合に発生します。これらの識別子はマクロとして定義されます。C 標準では、これらをオブジェクトとして再定義することは許可されていません。識別子のマクロ展開が発生する可能性がないような方法で識別子を使用します。

たとえば、外部変数 errno を参照します。

extern int errno;
しかし、errno は変数ではなくマクロとして発生します。

この欠陥が当てはまるマクロは、asserterrnomath_errhandlingsetjmpva_argva_copyva_end、および va_start です。チェッカーは、(ヘッダー ファイルではなく) ソース ファイル内にある欠陥のみを調べます。

リスク

C11 規格 (節 7.1.4) では、ほとんどのマクロをオブジェクトとして再定義することが許可されています。ソース ファイルのオブジェクトにアクセスし、マクロにアクセスしないようにするには、以下のいずれかを行います。

  • 識別子を外部変数または関数として再宣言する。

  • 関数形式のマクロについては、識別子名を小かっこで囲む。

オブジェクトとして再定義できないマクロにこれらの手法を使用しようとすると、エラーが発生します。

修正方法

マクロ展開が抑制されるような方法で識別子を使用しないようにします。

  • 識別子を外部変数または関数として再宣言しない。

  • 関数形式のマクロについては、マクロ名を小かっこで囲まない。

すべて展開する

#include<assert.h>
typedef void (*err_handler_func)(int);

extern void demo_handle_err(err_handler_func, int);

void func(int err_code) {
    extern void assert(int);   
    demo_handle_err(&(assert), err_code);
}

この例では、assert マクロが外部関数として再定義されています。demo_handle_err に引数として渡されると、識別子 assert が小かっこで囲まれることにより、assert マクロの使用が抑制されます。

修正 — assert をマクロとして使用

1 つの修正方法として、assert.h から assert マクロを直接使用します。関数 demo_handle_err の別の実装で、関数 assert のアドレスを取得するのではなく、assert を直接使用します。

#include<assert.h>
void demo_handle_err(int err_code) {
    assert(err_code == 0);                   
}

void func(int err_code) {
    demo_handle_err(err_code);          
}

結果情報

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

バージョン履歴

R2018a で導入