Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

It is necessary to understand how macro replacement works in C, particularly in the context of concatenating tokens using the ## operator and converting macro parameters to strings using the # operator.

Concatenating Tokens

Wiki MarkupThe {{\##}} preprocessing operator is used to merge two tokens into one while expanding macros. This is called token pasting or token concatenation. When a macro is expanded, the two tokens on either side of each ## operator are combined into a single token, which replaces the {{\##}} and the two original tokens in the macro expansion \[[FSF 05|AA. Bibliography#FSF 05]\macros, which is called token pasting or token concatenation. When a macro is expanded, the two tokens on either side of each ## operator are combined into a single token that replaces the ## and the two original tokens in the macro expansion [FSF 2005].

Token pasting is most useful when one or both of the tokens come from a macro argument. If either of the tokens next to an a ## is a parameter name, it is replaced by its actual argument before ## executes. The actual argument is not macro expanded first.

Stringification

Wiki MarkupParameters are not replaced inside string constants, but you can use the {{\#}} preprocessing operator can be used instead. When a macro parameter is used with a leading {{\#}}, the preprocessor replaces it with the literal text of the actual argument , converted to a string constant \ [[FSF 05|AA. Bibliography#FSF 05]\FSF 2005].

Noncompliant Code Example

The following definition for static_assert() from DCL03-C. Use a static assertion to test the value of a constant expression uses the JOIN() macro to concatenate the token assertion_failed_at_line_ with the value of __LINE__.:

Code Block

#define static_assert(e) \
  typedef char JOIN(assertion_failed_at_line_, __LINE__) \
    [(e) ? 1 : -1]

Wiki Markup{{\_\_LINE\_\_}} is a predefined macro names which expands to an integer constant representing the presumed line number of the current source line within the current source file \[[ISO/IEC 9899:1999|AA. Bibliography#ISO/IEC 9899-1999]\].macro name that expands to an integer constant representing the presumed line number of the current source line within the current source file. If the intention is to expand the __LINE__ macro, which is likely the case here, the following definition for JOIN() is noncompliant :

Code Block
bgColor#FFcccc

#define JOIN(x, y) x ## y

because the __LINE__ is not expanded, and the character array is subsequently named assertion_failed_at_line___LINE__.:

Code Block
bgColor#FFcccc
langc
#define JOIN(x, y) x ## y

 Compliant Compliant Solution

To get the macro to expand, a second level of indirection is required, as shown by this compliant solution:

Code Block
bgColor#ccccFF
langc#ccccff

#define JOIN(x, y) JOIN_AGAIN(x, y)
#define JOIN_AGAIN(x, y) x ## y

JOIN(x, y) calls JOIN_AGAIN(x, y) so that , if x or y is a macro, it is expanded before the ## operator pastes them together.

Note also that macro parameters cannot be individually parenthesized when concatenating tokens using the ## operator, converting macro parameters to strings using the # operator, or concatenating adjacent string literals. This is an exception, PRE01-C-EX2, to PRE01-C. Use parentheses within macros around parameter names.

...

This example is noncompliant if the programmer's intent is to expand the macro before stringification:

Code Block
bgColor#FFcccc
langc

#define str(s) #s
#define foo 4

str(foo)

...

To stringify the result of expansion of a macro argument, you must use two levels of macros must be used:

Code Block
bgColor#ccccFF
langc#ccccff

#define xstr(s) str(s)
#define str(s) #s
#define foo 4

The macro invocation xstr(foo) expands to 4. This is because s is stringified when it is used in str(), so it is not macro expanded first. However, s is an ordinary argument to xstr(), so it is completely macro expanded before xstr() is expanded. Consequently, by the time str() gets to its argument, it has already been macro expanded.

Risk Assessment

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

PRE05-C

low

Low

unlikely

Unlikely

medium

Medium

P2

L3

Automated Detection

ToolVersionCheckerDescription
Axivion Bauhaus Suite

Include Page
Axivion Bauhaus Suite_V
Axivion Bauhaus Suite_V

CertC-PRE05
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V
LANG.PREPROC.HASH
LANG.PREPROC.PASTE
Macro uses # operator
Macro uses ## operator
Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

C0341, C0342, C0801, C0802, C0803, C0811, C0872, C0880, C0881, C0884


Klocwork
Include Page
Klocwork_V
Klocwork_V
MISRA.DEFINE.SHARP.ORDER.2012
LDRA tool suite
Include Page
LDRA_V
LDRA_V

76 S, 125 S, 637 S

Enhanced Enforcement
PC-lint Plus

Include Page
PC-lint Plus_V
PC-lint Plus_V

9024

Assistance provided: reports any use of pasting or stringizing operators in a macro definition

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Other Languages

...

Related Guidelines

...

...

...

References

...

Bibliography

[FSF 2005]Section 3.4,

...

"

...

...

"
Section 3.5,

...

"

...


...

Image Added Image Added Image Added.html#Concatenation]" \[[ISO/IEC 9899:1999|AA. Bibliography#ISO/IEC 9899-1999]\] Section 6.10.3, "Macro replacement," Section 6.10.3.3, "The {{\##}} operator," Section 6.10.3.2, "The {{\#}} operator," Section 6.10.3.4, "Rescanning and further replacement," and Section 6.10.8, "Predefined macro names" \[[Saks 08|AA. Bibliography#Saks 08]\]Image Removed      01. Preprocessor (PRE)      PRE06-C. Enclose header files in an inclusion guard