cpp: Duplication of Side Effects
1
1 3.10.4 Duplication of Side Effects
1 ----------------------------------
1
1 Many C programs define a macro 'min', for "minimum", like this:
1
1 #define min(X, Y) ((X) < (Y) ? (X) : (Y))
1
1 When you use this macro with an argument containing a side effect, as
1 shown here,
1
1 next = min (x + y, foo (z));
1
1 it expands as follows:
1
1 next = ((x + y) < (foo (z)) ? (x + y) : (foo (z)));
1
1 where 'x + y' has been substituted for 'X' and 'foo (z)' for 'Y'.
1
1 The function 'foo' is used only once in the statement as it appears
1 in the program, but the expression 'foo (z)' has been substituted twice
1 into the macro expansion. As a result, 'foo' might be called two times
1 when the statement is executed. If it has side effects or if it takes a
1 long time to compute, the results might not be what you intended. We
1 say that 'min' is an "unsafe" macro.
1
1 The best solution to this problem is to define 'min' in a way that
1 computes the value of 'foo (z)' only once. The C language offers no
1 standard way to do this, but it can be done with GNU extensions as
1 follows:
1
1 #define min(X, Y) \
1 ({ typeof (X) x_ = (X); \
1 typeof (Y) y_ = (Y); \
1 (x_ < y_) ? x_ : y_; })
1
1 The '({ ... })' notation produces a compound statement that acts as
1 an expression. Its value is the value of its last statement. This
1 permits us to define local variables and assign each argument to one.
1 The local variables have underscores after their names to reduce the
1 risk of conflict with an identifier of wider scope (it is impossible to
1 avoid this entirely). Now each argument is evaluated exactly once.
1
1 If you do not wish to use GNU C extensions, the only solution is to
1 be careful when _using_ the macro 'min'. For example, you can calculate
1 the value of 'foo (z)', save it in a variable, and use that variable in
1 'min':
1
1 #define min(X, Y) ((X) < (Y) ? (X) : (Y))
1 ...
1 {
1 int tem = foo (z);
1 next = min (x + y, tem);
1 }
1
1 (where we assume that 'foo' returns type 'int').
1