[ was: Re: [RFC, doc] Note variable shadowing at max macro using statement expression ]
On 09-04-19 22:51, Sandra Loosemore wrote: > On 4/8/19 5:38 AM, Tom de Vries wrote: >> Hi, >> >> When suggesting to rewrite the unsafe (with respect to multiple >> evaluation of >> arguments) macro definition: >> ... >> #define max(a,b) ((a) > (b) ? (a) : (b)) >> ... >> into the safe macro definition: >> ... >> #define maxint(a,b) \ >> ({int _a = (a), _b = (b); _a > _b ? _a : _b; }) >> ... >> mention the variable shadowing problem for: >> ... >> #define maxint3(a, b, c) \ >> ({int _a = (a), _b = (b), _c = (c); maxint (maxint (_a, _b), _c); }) >> ... >> >> Any comments? > > The content looks reasonable, but I have some copy-editing nits. > Hi Sandra, thanks for the review. I've attached the updated patch, as well as the resulting relevant gcc.info portion. OK for trunk? Thanks, - Tom
[doc] Note variable shadowing at max macro using statement expression When suggesting to rewrite the unsafe (with respect to multiple evaluation of arguments) macro definition: ... #define max(a,b) ((a) > (b) ? (a) : (b)) ... into the safe macro definition: ... #define maxint(a,b) \ ({int _a = (a), _b = (b); _a > _b ? _a : _b; }) ... mention the variable shadowing problem for: ... #define maxint3(a, b, c) \ ({int _a = (a), _b = (b), _c = (c); maxint (maxint (_a, _b), _c); }) ... 2019-04-08 Tom de Vries <tdevr...@suse.de> * doc/extend.texi (@node Statement Exprs): Note variable shadowing at max macro using statement expression. --- gcc/doc/extend.texi | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 8e0deac26c3..cad7ad49e56 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -142,14 +142,36 @@ follows: @cindex side effects, macro argument But this definition computes either @var{a} or @var{b} twice, with bad results if the operand has side effects. In GNU C, if you know the -type of the operands (here taken as @code{int}), you can define -the macro safely as follows: +type of the operands (here taken as @code{int}), you can avoid this +problem by defining the macro as follows: @smallexample #define maxint(a,b) \ (@{int _a = (a), _b = (b); _a > _b ? _a : _b; @}) @end smallexample +Note that introducing variable declarations (as we do in @code{maxint}) can +cause variable shadowing, so while this example using the @code{max} macro +produces correct results: +@smallexample +int _a = 1, _b = 2, c; +c = max (_a, _b); +@end smallexample +@noindent +this example using maxint will not: +@smallexample +int _a = 1, _b = 2, c; +c = maxint (_a, _b); +@end smallexample + +This problem may for instance occur when we use this pattern recursively, like +so: + +@smallexample +#define maxint3(a, b, c) \ + (@{int _a = (a), _b = (b), _c = (c); maxint (maxint (_a, _b), _c); @}) +@end smallexample + Embedded statements are not allowed in constant expressions, such as the value of an enumeration constant, the width of a bit-field, or the initial value of a static variable.
This feature is especially useful in making macro definitions "safe" (so that they evaluate each operand exactly once). For example, the "maximum" function is commonly defined as a macro in standard C as follows: #define max(a,b) ((a) > (b) ? (a) : (b)) But this definition computes either A or B twice, with bad results if the operand has side effects. In GNU C, if you know the type of the operands (here taken as 'int'), you can avoid this problem by defining the macro as follows: #define maxint(a,b) \ ({int _a = (a), _b = (b); _a > _b ? _a : _b; }) Note that introducing variable declarations (as we do in 'maxint') can cause variable shadowing, so while this example using the 'max' macro produces correct results: int _a = 1, _b = 2, c; c = max (_a, _b); this example using maxint will not: int _a = 1, _b = 2, c; c = maxint (_a, _b); This problem may for instance occur when we use this pattern recursively, like so: #define maxint3(a, b, c) \ ({int _a = (a), _b = (b), _c = (c); maxint (maxint (_a, _b), _c); })