Main Content

CERT C: Rec. PRE05-C

Understand macro replacement when concatenating tokens or performing stringification

Since R2024b

Description

Rule Definition

Understand macro replacement when concatenating tokens or performing stringification.1

Polyspace Implementation

This checker checks for Incorrectly Expanded Macros.

Examples

expand all

Issue

The issue occurs when an operand of the # or ## operators inside a macro is itself a macro, which might result in an unexpected macro expansion.

Polyspace reports a violation for the operand of the ## that is itself a macro even if the result of the concatenation is a valid identifier, such as a macro or variable name.

Risk

The token pasting operator ## concatenates its operands when the macro is expanded. If one of the operands is an expandable macro argument, that operand is not expanded before the concatenation operation.

In the case of the # operator, which converts its argument into a string, the operation returns the parameter name as a string instead of converting the expanded parameter to a string.

Fix

To correctly expand a macro parameter that you use as an operand of the # or ## operators, introduce a second intermediate macro that expands the argument before you pass it to the macro that uses the # or ## operators.

Example — Incorrectly Expanded Macro Parameters
#include <stdio.h>

#define DECLARE_VAR(type, counter) type var##counter
#define msg "Message emmitted on this line: "
#define TOSTRING(str) #str

void print_location()
{

    const char *message = msg TOSTRING(__LINE__); // Noncompliant
    printf("%s\n", message);
    // Prints: "Message emmitted on this line: __LINE__"

}
void create_variables()
{
    DECLARE_VAR(int, __COUNTER__) = 1;        // Noncompliant
    // Expands to int var__COUNTER__ = 1
    DECLARE_VAR(float, __COUNTER__) = 3.1459;    // Noncompliant
    // Expands to float var__COUNTER__ = 3.1459
}

In this example, Polyspace reports a violation for the declaration of the variable message inside the function print_location(). The argument __LINE__ of the macro TOSTRING is not expanded when it is appended to msg because __LINE__ is an argument of the # operator.

Similarly, Polyspace reports violations for the use the macro DECLARE_VAR inside the function create_variables(). In both declarations, the argument __COUNTER__ is not expanded because it is an operand of the ## operator.

Correction — Expand Macro Argument Is Second Level Macro

One possible correction is to introduce a second level of indirection for the macros that use the # or ## operators, so that the argument expands in the second level macro before that second level macro calls the macro with the # or ## operators. For example, you can define a macro DECLARE_VAR_EXPAND(type, counter) which calls the macro DECLARE_VAR(type, counter). The variable __COUNTER__ then expands correctly in the call DECLARE_VAR_EXPAND(int, __COUNTER__) before DECLARE_VAR(type, counter) performs a concatenation with var.

#include <stdio.h>

#define DECLARE_VAR_EXPAND(type, counter) DECLARE_VAR(type, counter)
#define DECLARE_VAR(type, counter) type var##counter
#define msg "Message emmitted on this line: "
#define TOSTRING_EXPAND(x) TOSTRING(x)
#define TOSTRING(str) #str

void print_location()
{

    const char *message = msg TOSTRING_EXPAND(__LINE__); // Compliant
    printf("%s\n", message);
    // Prints: "Message emmitted on this line: 12"

}
void create_variables()
{
    DECLARE_VAR_EXPAND(int, __COUNTER__) = 1;        // Compliant
    // Expands to int var1 = 1
    DECLARE_VAR_EXPAND(float, __COUNTER__) = 3.1459;    // Compliant
    // Expands to float var2 = 3.1459
}

Check Information

Group: Rec. 01. Preprocessor (PRE)

Version History

Introduced in R2024b


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.