Versions Compared

Key

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

Macros are frequently used to make source code more readable. Macro definitions, regardless of whether they expand to a single or multiple statements (see , should not conclude with a semicolon. (See PRE10-C. Multi-statement macros should be enclosed Wrap multistatement macros in a do-while loop.) should not conclude with a semicolon. If required, the semicolon should be included following the macro expansion. Inadvertently inserting a semicolon at the end of the macro definition can unexpectedly change the control flow of the program.

...

This noncompliant code example creates a macro definition for a for loop in the program. A for loop should require braces, even if it contains only a single body statement. (See EXP19-C. Use braces for the body of an if, for, or while statement.) This macro takes an integer argument, which is the number of times the loop should run. The programmer has provided inserted a semicolon at the end of the macro definition by mistake.

Code Block
bgColor#FFCCCC
langc

#define FOR_LOOP(n)  for(i=0; i<(n); i++);

int i;
FOR_LOOP(3)
{
  puts("Inside for loop\n");
}

The programmer expects to get the following output from the code:

Code Block

Inside for loop
Inside for loop
Inside for loop

But because of the semicolon at the end of the macro definition, the for loop in the program has a null statement, so the statement "Inside for loop" gets printed just once. Essentially, the semicolon at the end of the macro definition changes the program control flow.

Though the above Although this example might not actually be used in code, it shows the effect a semicolon in a macro definition can have.

...

The compliant solution is to write the macro definition without the semicolon at the end, leaving the decision to whether or not to have a semicolon or not up to the person who is using the macro.:

Code Block
bgColor#CCCCFF
langc

#define FOR_LOOP(n)  for(i=0; i<(n); i++)

int i;
FOR_LOOP(3)
{
  puts("Inside for loop\n");
}

...

In this noncompliant code example, the programmer defines a macro which that increments the value of the first argument, x, by one 1 and modulates it with the value of the 2nd second argument, max.:

Code Block
bgColor#FFCCCC
langc

#define INCREMENTINCREMOD(x, max) ((x) = ((x) + 1) % (max));

int index = 0;
int value;
value = INCREMENTINCREMOD(index, 10) + 2;
/* ... */

In this case, the programmer intends to increment index and then use that as a value by adding 2 to it. Unfortunately, the value is equal to the incremented value of index because of the semicolon present at the end of the macro. The '+ 2;' is treated as a separate statement by the compiler. The user will not get any compilation errors. If the user has not enabled warnings while compiling, the effect of the semicolon in the macro cannot be detected at an early stage.

...

The compliant solution is to write the macro definition without the semicolon at the end, leaving the decision whether or not to have a semicolon or not up to the person who is using the macro.:

Code Block
bgColor#CCCCFF
langc

#define INCREMENTINCREMOD(x, max) ((x) = ((x) + 1) % (max))

Compliant Solution

This compliant solution uses an inline function as recommended by PRE00-C. Prefer inline or static functions to function-like macros.

Code Block
bgColor#CCCCFF
langc
inline int incremod(int *x, int max) {*x = (*x + 1) % max;}

Risk Assessment

Using a semicolon at the end of a macro definition can result in the change of program control flow and thus unintended program behavior.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

PRE11-C

medium

Medium

probable

Probable

low

Low

P12

L1

Automated Detection

ToolVersionCheckerDescription
Astrée
Include Page
Astrée_V
Astrée_V
macro-final-semicolonFully checked
Axivion Bauhaus Suite

Include Page
Axivion Bauhaus Suite_V
Axivion Bauhaus Suite_V

CertC-PRE11
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V
LANG.PREPROC.MACROENDMacro Does Not End With ) or }
Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

C3412
LDRA tool suite
Include Page
LDRA_V
LDRA_V
79 SEnhanced Enforcement
PC-lint Plus

Include Page
PC-lint Plus_V
PC-lint Plus_V

823

Fully supported

Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C: Rec. PRE11-CChecks for macros terminated with semicolons (rule fully covered)
RuleChecker
Include Page
RuleChecker_V
RuleChecker_V
macro-final-semicolon Fully checked

Related Vulnerabilities

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

Other Languages

...

Related Guidelines

...

...

...

...


...

Image Added Image Added .PRE10-C. Wrap multi-statement macros in a do-while loop      01. Preprocessor (PRE)      Image Modified