The C Standard defines a set of predefined macros (see subclause 6.10.8) to help the user determine if the implementation being used is a conforming implementation, and if so, to which version of the C Standard it conforms. These macros can also help the user to determine which of the standard features are implemented.
The tables below list these macros and which version of the C Standard they were introduced. The following macros are required in C11.
| C89 | C99 | C11 |
|
| C99 | C11 |
| (C94) | C99 | C11 |
| C89 | C99 | C11 |
| C89 | C99 | C11 |
| C89 | C99 | C11 |
| C89 | C99 | C11 |
The following are optional environment macros in C11.
|
| C99 | C11 |
|
| C99 | C11 |
|
|
| C11 |
|
|
| C11 |
The following are optional feature macros in C11.
|
|
| C11 |
|
| C99 | C11 |
|
| C99 | C11 |
|
|
| C11 |
|
|
| C11 |
|
|
| C11 |
|
|
| C11 |
|
|
| C11 |
The following is optional in C11 and is defined by the user:
__STDC_WANT_LIB_EXT1__ | C11 |
Noncompliant Code Example (Checking value of predefined macro)
The value a C Standard predefined macro should never be tested for a value before the macro is tested to make sure it is defined, as shown in this noncompliant code example:
#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; }
Compliant Solution (Testing for definition of macro)
In this compliant solution, the definition of the predefined macro __STDC__
is tested before the value of the macro is tested:
#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; }
Compliant Solution (Test for Optional feature)
This compliant solution tests to see if the C11 predefined macro __STDC_ANALYZABLE__
is defined and what value the implementation has given the macro:
#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; }
Compliant Solution (Optional Language Features)
This compliant solution checks for the C11 optional language features in Annex K. If Annex K is supported by the implementation, the functions defined in Annex K are used, if Annex K is not supported, then the Standard library functions are used. (See DCL09-C. Declare functions that return errno with a return type of errno_t.)
#if defined(__STDC_LIB_EXT1__) #if (__STDC_LIB_EXT1__ >= 201112L) #define USE_EXT1 1 #define __STDC_WANT_LIB_EXT1__ 1 /* want the ext1 functions */ #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; }
Risk Assessment
Not testing for language features, or the version of the implementation being used can lead to unexpected or undefined program behavior.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
PRE13-C | low | probable | low | P6 | L2 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
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" |