JPCERT コーディネーションセンター

PRE13-C. あらかじめ定義された標準マクロで準拠規格やバージョンを確認する

C 言語規格では、現在使っている処理系が規格合致処理系であるかどうか、そして言語規格のどのバージョンに準拠しているのか、を調べられるように、いくつかのマクロをあらかじめ定義している(C言語規格 6.10.8 を参照)。また、これらのマクロは、C 言語規格のどの機能を処理系がサポートしているか調べるためにも使える。

マクロ名とそのマクロが導入された C 言語規格を以下に示す。最初の表は必須とされているマクロについてである。

マクロ名 C90 C99 C11

__STDC__

__STDC_HOSTED__

 

__STDC_VERSION__1

 

__DATE__

__FILE__

__LINE__

__TIME__

  1) __STDC_VERSION__ は C90 への追補で導入された。このバージョンは C94 と呼ばれている。

次の表は、処理系の実装形態に応じて定義されるマクロである。

マクロ名 C90 C99 C11

__STDC_ISO_10646__

 

__STDC_MB_MIGHT_NEQ_WC__

 

__STDC_UTF_16__

 

 

__STDC_UTF_32__

 

 

次の表は、処理系がサポートしている機能に応じて定義されるマクロを示す。

マクロ名 C90 C99 C11

__STDC_ANALYZABLE__

 

 

__STDC_IEC_559__

 

__STDC_IEC_559_COMPLEX__

 

__STDC_LIB_EXT1__ 

 

 

__STDC_NO_ATOMICS__

 

 

__STDC_NO_COMPLEX__

 

 

__STDC_NO_THREADS__

 

 

__STDC_NO_VLA__ 

 

 

次の表は、必要に応じてユーザが定義すべきマクロである。

マクロ名 C90 C99 C11
__STDC_WANT_LIB_EXT1__       
違反コード (あらかじめ定義されたマクロの値の評価)

C 言語規格であらかじめ定義されたマクロ名について、マクロとして定義されているかどうかを確認せずにその値を評価してはならない。

#include <stdio.h>

int main(void) {
  #if (__STDC__ == 1)
    printf("Implementation is ISO-conforming.\n");
  #else
    printf("Implementation is not ISO-conforming.\n");
  #endif
  /* ... */

  return 0;
}
適合コード (マクロ定義を確認する)

以下の適合コードでは、マクロ __STDC__ が定義されているかどうかを最初に確認し、その後でその値を評価している。

#include <stdio.h>

int main(void) {
  #if defined(__STDC__)
    #if (__STDC__ == 1)
      printf("Implementation is ISO-conforming.\n");
    #else
      printf("Implementation is not ISO-conforming.\n");
    #endif
  #else   /* !defined(__STDC__) */
    printf("__STDC__ is not defined.\n");
  #endif
  /* ... */
  return 0;
}
適合コード (省略可能な機能の検査)

以下の適合コードでは、C11 で定義されたマクロ __STDC_ANALYZABLE__ が定義されているかどうかを確認し、マクロが定義されている場合にだけその値を評価している。

#include <stdio.h>

int main(void) {
  #if defined (__STDC__)
    #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)  /* C11 */
      #if defined(__STDC_ANALYZABLE__)
        #if (__STDC_ANALYZABLE__ == 1)
	      printf("Compiler conforms to Annex L (Analyzability).\n");
        #else
	      printf("Compiler does not support Annex L (Analyzability).\n");
        #endif
      #else
        printf("__STDC_ANALYZABLE__ is not defined.\n");
      #endif
    #else
      printf("Compiler not C11.\n");
    #endif
  #else
    printf("Compiler not Standard C.\n");
  #endif

  return 0;
}
適合コード (省略可能な言語機能)

以下の適合コードでは、C11 の Annex K で規定されている省略可能な言語機能をサポートしているかどうかを確認している。処理系が Annex K をサポートしている場合には Annex K で規定されている関数を使い、Annex K をサポートしていない場合には標準ライブラリ関数を使っている。(「DCL09-C. errno を返す関数は返り値を errno_t 型として定義する」を参照。)

#if defined(__STDC_LIB_EXT1__)
  #if (__STDC_LIB_EXT1__ >= 201112L)
    #define USE_EXT1 1
    #define __STDC_WANT_LIB_EXT1__ 1 /* ext1 関数群を使いたい */
  #endif
#endif

#include <string.h>
#include <stdlib.h>

int main(void) {
  char source_msg[] = "This is a test.";
  char *msg = malloc(sizeof(source_msg) + 1);

  if (msg != NULL) {
    #if defined(USE_EXT1)
      strcpy_s(msg, sizeof msg, source_msg);
    #else
      strcpy(msg, source_msg);
    #endif
  }
  else {
    return EXIT_FAILURE;
  }
  return 0;
}
リスク評価

C 言語規格に定められた言語機能のなかには、その機能を処理系がサポートしているか、また、サポートしているバージョンはなにか、を確認しないで使うと意図しない動作や未定義の動作を引き起こすようなものがある。

ルール

深刻度

可能性

修正コスト

優先度

レベル

PRE13-C

P6

L2

関連するガイドライン
[ISO/IEC TR 24772:2013] Pre-processor Directives [NMP]
[ISO/IEC 9899:2011]

6.10.8, "Predefined macro names"

K.3.7.1, "Copying functions"

翻訳元

これは以下のページを翻訳したものです。

PRE13-C. Use the Standard predefined macros to test for versions and features. (revision 6)

Top へ

Topへ
最新情報(RSSメーリングリストTwitter