Add section on the misuse of macros.
This commit is contained in:
parent
4d7432da07
commit
e3718be004
1 changed files with 82 additions and 0 deletions
|
@ -51,3 +51,85 @@ careful analysis and comparison with the compiler documentation
|
||||||
is required to check if propagating the attribute is
|
is required to check if propagating the attribute is
|
||||||
appropriate. Incorrectly applied attributes can result in
|
appropriate. Incorrectly applied attributes can result in
|
||||||
undesired behavioral changes in the compiled code.
|
undesired behavioral changes in the compiled code.
|
||||||
|
|
||||||
|
[[sect-Defensive_Coding-C-Common-Mistakes]]
|
||||||
|
=== Common mistakes
|
||||||
|
|
||||||
|
==== Mistakes in macros
|
||||||
|
A macro is a name given to a block of C statements as a pre-processor
|
||||||
|
directive. Being a pre-processor the block of code is transformed by
|
||||||
|
the compiler before being compiled.
|
||||||
|
|
||||||
|
A macro starts with the preprocessor directive, #define. It can
|
||||||
|
define a single value or any 'substitution', syntactically valid or
|
||||||
|
not.
|
||||||
|
|
||||||
|
A common mistake when working with macros is that programmers treat
|
||||||
|
arguments to macros like they would functions. This becomes an issue
|
||||||
|
when the argument may be expanded multiple times in a macro.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
macro-misuse.c
|
||||||
|
[source,C]
|
||||||
|
----
|
||||||
|
#define simple(thing) do { \
|
||||||
|
if (thing < 1) { \
|
||||||
|
y = thing; \
|
||||||
|
} \
|
||||||
|
else if (thing > 100) { \
|
||||||
|
y = thing * 2 + thing; \
|
||||||
|
} \
|
||||||
|
else { \
|
||||||
|
y = 200; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
int x = 200;
|
||||||
|
int y = 0;
|
||||||
|
simple(x++);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
Each pass through the simple() macro would mean that x could be
|
||||||
|
expanded in-place each time 'thing' was mentioned.
|
||||||
|
|
||||||
|
The 'main' function would be processed and expanded as follows:
|
||||||
|
|
||||||
|
macro-misuse-post-processing.c
|
||||||
|
[source,C]
|
||||||
|
----
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
int x = 200;
|
||||||
|
int y = 0;
|
||||||
|
do {
|
||||||
|
if ( x++ < 1) {
|
||||||
|
y = x++;
|
||||||
|
}
|
||||||
|
else if (thing > 100) {
|
||||||
|
y = x++ * 2 + x++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
x = 200;
|
||||||
|
}
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
Each evaluation of the argument to 'simple' (x++) would be executed
|
||||||
|
each time it was referenced.
|
||||||
|
|
||||||
|
While this may be 'expected' behaviour by the original creator, large
|
||||||
|
projects may have programmers who were unaware of how the macro may
|
||||||
|
expand and this may introduce unexpected behaviour, especially if the
|
||||||
|
value is later used as indexing into an array or able to be
|
||||||
|
overflowed.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue