Macros are often frequently used to generalize several segments of code which might be used multiple times in the code. This guideline focuses on the macros consisting of single statements which do not usually require to be enclose in a do()....while()
. (See also make source code more readable. Macro definitions, regardless of whether they expand to a single or multiple statements, should not conclude with a semicolon. (See PRE10-C. Wrap multi-statement multistatement macros in a do-while loop.) When writing macros, a good C programmer should not include semicolon at the end of macro definition. The use of semicolon should be taken care while usage of the macro. The trailing If required, the semicolon should be included following the macro expansion. Inadvertently inserting a semicolon at the end of the macro definition can sometimes unexpectedly change the control flow of the program depending upon its usage in the program code.
Other ways Another way to avoid this kind of problem would be is to prefer inline or static functions over function-like macros. (See also PRE00-C. Prefer inline or static functions to function-like macros.)
In general, the programmer should ensure that there is no semicolon at the end of a macro definition. The responsibility for having a semicolon where needed during the use of such a macro should be delegated to the person invoking the macro.
Noncompliant Code Example
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 user programmer has provided inserted a semicolon at the end of the macro definition by mistake.
Code Block | ||||
---|---|---|---|---|
| ||||
#define FOR_LOOP(n) for(i=0; i<(n); i++); main() { int i; FOR_LOOP(3) { printfputs("Inside for loop\n"); } } |
The user assumes programmer expects to get the following output from the code:
Code Block |
---|
Inside for loop
Inside for loop
Inside for loop
|
But unfortunately because of the semicolon at the end of the macro definition, the for
loop in the program has a null statement and then , 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 so often by programmers, it shows the side effect a semicolon in a macro definition can have.
Compliant Solution
The compliant solution would be is to write the macro definitions definition without the semicolon at the end and , leaving the decision to whether or not to have a semicolon or not up to the user person who is using the macro.:
Code Block | ||||
---|---|---|---|---|
| ||||
#define FOR_LOOP(n) for(i=0; i<(n); i++) main() { int i; FOR_LOOP(3) { printfputs("Inside for loop\n"); } } |
Noncompliant Code Example
In the this noncompliant code belowexample, the programmer defines a macro which that increments the value in of the first argument, x
, by 1 by one and then wraps modulates it along with the max value provided by the user.of the second argument, max
:
Code Block | ||||
---|---|---|---|---|
| ||||
#define INCREMENTINCREMOD(x, max) ((x) = ((x) + 1) % (max)); main() { int index = 0; int value; value = INCREMENTINCREMOD(index, 10) + 2; ./* .......... ........... } */ |
In the above codethis case, the programmer intends to increment the index
and then use that as a value by adding 2 to it. Unfortunately, the value will always be is equal to the incremented value of index
because of the semicolon present at the end of the macro. The '+ 2;'
will be is treated as another 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 can not cannot be detected at an early stage.
Compliant Solution
The compliant solution would be is to write the macro definitions definition without the semicolon at the end and , leaving the decision whether or not to have a semicolon or not up to the user while person who is using the macro. :
Code Block | ||||
---|---|---|---|---|
| ||||
#define INCREMENTINCREMOD(x, max) ((x) = ((x) + 1) % (max)) main() { int index = 0; int value; value = INCREMENT(index, 10) + 2; ......... .......... } |
Mitigation Strategies
The programmer should ensure that there is no semicolon
at the end of the macro definition with single statement. The responsibility of having a semicolon
where needed during the use of the macro should be given to the user using the macro.
Risk Assessment
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 | ||||
---|---|---|---|---|
| ||||
inline int incremod(int *x, int max) {*x = (*x + 1) % max;} |
Risk Assessment
Using a semicolon at the end of a Using semicolon at the end of the 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 |
Probable |
Low | P12 | L1 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Astrée |
| macro-final-semicolon | Fully checked | ||||||
Axivion Bauhaus Suite |
| CertC-PRE11 | |||||||
CodeSonar |
| LANG.PREPROC.MACROEND | Macro Does Not End With ) or } | ||||||
Helix QAC |
| C3412 | |||||||
LDRA tool suite |
| 79 S | Enhanced Enforcement | ||||||
PC-lint Plus |
| 823 | Fully supported | ||||||
Polyspace Bug Finder |
| CERT C: Rec. PRE11-C | Checks for macros terminated with semicolons (rule fully covered) | ||||||
RuleChecker |
| macro-final-semicolon | Fully checked |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
...
PRE10-C. Wrap multi-statement macros in a do-while loop 01. Preprocessor (PRE) PRE12-C. Define numeric constants in a portable way