Reputation: 4809
Often and often I felt some of the parentheses around arguments in macro definitions were redundant. It’s too inconvenient to parenthesize everything. If I can guarantee the argument needs not be parenthesized, can I omit the parentheses? Or is parenthesizing them all highly recommended?
I came up with this question when I wrote:
#define SWAP_REAL(a, b, temp) do{double temp = a; a = b; b= temp;}while(0)
I think that if an argument appears as an l-value in the macro, the parentheses can be omitted because that means the argument appears with no other operation.
My reasoning is:
You cannot confuse the compiler into thinking that your argument is an expression with a comma in it. For example, SWAP(a, b, b)
will not be interpreted successfully as
do{double temp = a, b; a, b = b; b= temp;}while(0)
which can pass compilation.
Am I right? Can anyone give me a counter-example?
In the following example,
#define ADD(a, b) (a += (b))
I think the argument a
needn’t be parenthesized. And in this specific case, neither needs the argument b
, right?
@JaredPar:
#include <stdio.h> #define ADD(a, b) (a += (b)) int main(){ int a = 0, b = 1; ADD(a; b, 2); return 0; }
This cannot be compiled successfully on my VS2010. Error C2143: syntax error : missing ')' before ';'
In a nutshell, you don’t need to parenthesize the arguments having appeared as an l-value in the macro, but you are highly recommended to parenthesize them all.
Rules of Macros:
Upvotes: 4
Views: 4971
Reputation: 755094
There are macros where you're concatenating elements to make a string (perhaps using the #
operator), or building identifiers out of macro arguments using the ##
operator. In such cases, you don't parenthesize the arguments.
Also, I think that when the macro arguments are themselves passed as function arguments, then you don't absolutely have to parenthesize them:
#define CALLOC(s, n) calloc(s, n)
You can play fiendish games calling such a macro (CALLOC({3, 4})
), but you get what you deserve (a compilation error) — I'm not aware of a way of calling that macro that would work if instead of the macro you wrote the same arguments as a direct call to calloc()
.
However, if you are using the arguments in most arithmetic expressions, then you do need to wrap them in parentheses:
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
Obviously, if you invoke it with arguments with side effects, then you get what you get. But the arguments won't be misinterpreted as they could be if you wrote:
#define MIN(x, y) x < y ? x : y
and then invoked it as:
MIN(x = 3 * y + 1, y = 2 * x - 2);
The comment by Moon suggests a SWAP_INT
macro.
The following code using that macro compiles cleanly when compiled using default options, but fails to compile with -DWITH_PARENTHESES
set.
#include <stdio.h>
#ifdef WITH_PARENTHESES
#define SWAP_INT(a, b) do { int temp = (a); (a) = (b); (b) = temp; } while (0)
#else
#define SWAP_INT(a, b) do { int temp = a; a = b; b = temp; } while (0)
#endif
int main(void)
{
int p = 319;
int q = 9923;
int x = 23;
int y = 300;
printf("p = %8d, q = %8d, x = %8d, y = %8d\n", p, q, x, y);
SWAP_INT(p, q); // OK both ways
SWAP_INT(x, y); // OK both ways
printf("p = %8d, q = %8d, x = %8d, y = %8d\n", p, q, x, y);
SWAP_INT(x /= y, p *= q); // Compiles without parentheses; fails with them
printf("p = %8d, q = %8d, x = %8d, y = %8d\n", p, q, x, y);
return 0;
}
The output:
p = 319, q = 9923, x = 23, y = 300
p = 9923, q = 319, x = 300, y = 23
p = 41150681, q = 13, x = 0, y = 3165437
That isn't a safe or effective way of swapping integers — the macro without the parentheses is not a good idea.
JFTR: when compiled without -DWITH_PARENTHESES
, the line for the macro with the expressions is inscrutable:
do { int temp = x /= y; x /= y = p *= q; p *= q = temp; } while (0);
Normally, a swap macro expects two variable names — or array elements, or structure or union members, or any mix of these. It does not expect to be given arbitrary expressions. The parentheses ensure that the assignment to x /= y
(which is not an lvalue) fails; without the parentheses, the expression is interpreted, but it isn't anything like what was intended (if, indeed, anything could be intended when 'swapping' two expressions like that).
Upvotes: 2
Reputation: 60848
It's unsafe to omit if you use any operator that isn't lowest precedence in your expression. I believe that would be comma.
a op b
where op
is some operator like +
, *
etc. will always bind wrong if a
contains an expression of low precedence like 1 || 2
.
Note I'm not claiming it's safe in those cases. There are more creative ways to break macros. By the way, don't use macros with side effects in the first place. More generally, don't use macros as functions. (See, e.g., Effective C++).
Upvotes: 3
Reputation: 755587
Here is one case where it makes a demonstrable difference
ADD(x;y, 42)
With parens this leads to a compilation error but without it leads to code that compiles.
(x;y) += 42; // With parens errors
x;y += 42; // Without parens compiles
This may look like a silly example but it's possible combining macros together can easily lead to strange code expressions like the above.
Why take the chance here? It's just 2 characters
Upvotes: 4