Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

Comments on When should I parenthesize macro arguments in C?

Parent

When should I parenthesize macro arguments in C?

+5
−0

I've seen macros use parentheses to enclose its arguments. Most of these make sense, as in

#define sum(a, b)  ((a) + (b))

The outer prevents the following:

#define sum_bad(a, b)  (a) + (b)

s = sum_bad(x, y) * z;  // (x) + (y) * z

The inner prevents the following:

#define mul_bad(a, b)  (a * b)

m = mul_bad(x, y + z);  // (x * y + z)

However, I've seen some parentheses that don't seem justified.

#define foo(a, b)  bar((a), (b))  // Why not just `bar(a, b)`
#define asd(a, b)  do \
{
    int x = (b);  // Why not just `= b;`?

    zxc(x);
} while (0)

Is it really necessary to always enclose macro arguments in parentheses, or is it superfluous in some cases?

History
Why does this post require attention from curators or moderators?
You might want to add some details to your flag.
Why should this post be closed?

0 comment threads

Post
+2
−0

With macros, you are better off using parens at any time you use one of the parameters in an expression context.

The problem with operator precedence is not limited to + and *. Did you know that comma (,) is an operator? Did you know that comma has a lower precedence than assignment? Did you know that assignment is considered an operator in C?

Did you know that comma is also used to declare multiple variables of the same type?

What does the expression x = a, b do? What about int x = a, b; ?

In general, if you are using macro parameters as "values", you should go ahead and parenthesize them. It generally doesn't hurt, and it might help.

Only if you are using macro parameters as text or code or strings should you (maybe) not parenthesize them. That is, if you are using a macro parameter to construct a name, like:

#define unique_name(base) base ## __COUNTER__

then don't use parens, because you want the "raw" value of base (and because it wouldn't make sense with parens). Likewise if you are stringizing the parameter:

#define DO_PRAGMA(x) _Pragma (#x)

then don't use parens, because you don't want parens in the string you are creating. (Or, if you do want them, then go ahead!) Also, parens interfere with string literal concatenation. So it's generally better to leave stringized expressions bare. And finally if the parameter is itself code, not an expression:

#define DO_ONCE(code, ...) do code, ## __VA_ARGS__ while(0)

then don't use parens because they are likely to be invalid syntax. Maybe use braces {...} instead. (But really that's a horrible macro that I just made up to make a point. Don't do things like that in real life!)

History
Why does this post require attention from curators or moderators?
You might want to add some details to your flag.

1 comment thread

The comma operator can't appear in a macro replacement argument, I think (4 comments)
The comma operator can't appear in a macro replacement argument, I think
alx‭ wrote 12 months ago · edited 12 months ago

But in function argument lists, the comma operator cannot appear, so in a replacement, the comma operator will never appear in the top level, right?

That is, how can I embed a comma operator in a macro call that could possibly interfere with the macro body?

macro(a, (b, c));

That is the only way I can think of, but since it already parenthesizes in the argument list, it's safe. And if it doesn't parenthesize, it is interpreted as a different argument, not a comma operator.

I don't see the possibility of danger.

Lundin‭ wrote 12 months ago · edited 12 months ago

alx‭ That's correct. The syntax for calling a function-like macro contains commas in itself so we can't pass comma operator arguments without surrounding the argument with parenthesis. The formal syntax is identifier-list: which can either be identifier or identifier-list , identifier.

aghast‭ wrote 12 months ago

When I say gcc -E -xc - and type:

#define FOO(x) x+1
#define BAR(x) x,1
int y = FOO(BAR(10));

I get back:

int y = 10,1 +1;

If I say

#define LIST3(delim, a, b, c) a delim b delim c      
#define INIT3(a, b, c) { LIST3(COMMA, a, b, c) }
#define COMMA ,
int x[] = INIT3(10, 20, 30);

I get back

int x[] = { 10 , 20 , 30 };

If the comma is part of a macro parameter, it doesn't participate in argument recognition. If the comma is part of the replacement text of a later-evaluated macro, it doesn't participate in argument recognition. If a macro name and parameter list are expanded as part of different elements, the expansion of the macro will be delayed until the second stage of expansion, thus avoiding participating in first-stage argument recognition.

Anyway, the lesson stands: if you are using a macro argument as a member of an expression, then wrap it in parens. If that habit costs you a couple of mips, so what? Mips are cheap!

alx‭ wrote 12 months ago · edited 12 months ago

Very interesting hacks about commas with macros! I'd say if you write a macro that expands to something with a comma operator, you either want that hack explicitly for some obscure reason, or should be using parens in that macro so that it doesn't misbehave with other macros. But yeah, very interesting trick. :)