PRE13-C. あらかじめ定義された標準マクロで準拠規格やバージョンを確認する
C 言語規格では、現在使っている処理系が規格合致処理系であるかどうか、そして言語規格のどのバージョンに準拠しているのか、を調べられるように、いくつかのマクロをあらかじめ定義している(C言語規格 6.10.8 を参照)。また、これらのマクロは、C 言語規格のどの機能を処理系がサポートしているか調べるためにも使える。
マクロ名とそのマクロが導入された C 言語規格を以下に示す。最初の表は必須とされているマクロについてである。
マクロ名 | C90 | C99 | C11 |
---|---|---|---|
|
✓ |
✓ |
✓ |
|
|
✓ |
✓ |
|
|
✓ |
✓ |
|
✓ |
✓ |
✓ |
|
✓ |
✓ |
✓ |
|
✓ |
✓ |
✓ |
|
✓ |
✓ |
✓ |
1) __STDC_VERSION__ は C90 への追補で導入された。このバージョンは C94 と呼ばれている。
次の表は、処理系の実装形態に応じて定義されるマクロである。
マクロ名 | C90 | C99 | C11 |
---|---|---|---|
|
|
✓ |
✓ |
|
|
✓ |
✓ |
|
|
|
✓ |
|
|
|
✓ |
次の表は、処理系がサポートしている機能に応じて定義されるマクロを示す。
マクロ名 | C90 | C99 | C11 |
---|---|---|---|
|
|
|
✓ |
|
|
✓ |
✓ |
|
|
✓ |
✓ |
|
|
|
✓ |
|
|
|
✓ |
|
|
|
✓ |
|
|
|
✓ |
|
|
|
✓ |
次の表は、必要に応じてユーザが定義すべきマクロである。
マクロ名 | 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)