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. C References#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 comes 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. C References#FSF 05]\].

...

2005].

Noncompliant Code Example

The following definition for static_assert() from DCL03-AC. 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]

...

{{\_\_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. C References#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 non-compliant:

Code Block
bgColor#FFcccc

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

noncompliant 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 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, they are 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-AC. Use parentheses within macros around parameter names.

...

Noncompliant Code Example

This example is non-compliant 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)

The macro invocation str(foo) expands to "foo".

Compliant Solution

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

Code Block
bgColor#ccccFF
lang#ccccffc

#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-

A

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.

References

...

Related Guidelines

Bibliography

[FSF 2005]Section

...

3.4,

...

"

...

Stringification"
Section 3.5,

...

"

...


...

Image Added Image Added Image Added.html#Concatenation]" \[[ISO/IEC 9899:1999|AA. C References#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. C References#Saks 08]\] Dan Saks, Stephen C. Dewhurst. Presentation. Sooner Rather Than Later: Static Programming Techniques for C++.PRE04-A. Do not reuse a standard header file name      01. Preprocessor (PRE)       PRE06-A. Enclose header files in an inclusion guard