在 C 中总是将定义括在括号中是否有充分的理由?
显然,有时 #define
语句必须带有括号,如下所示:
#define WIDTH 80+20
int a = WIDTH * 2; // expect a==200 but a==120
所以我总是加上括号,即使它只是一个数字:
#define WIDTH (100)
C 新手问我为什么这样做,所以我尝试了找到一种边缘情况,其中单个数字 #define
上缺少括号会导致问题,但我想不出一个。
这样的事例存在吗?
Clearly, there are times where #define
statements must have parentheses, like so:
#define WIDTH 80+20
int a = WIDTH * 2; // expect a==200 but a==120
So I always parenthesize, even when it's just a single number:
#define WIDTH (100)
Someone new to C asked me why I do this, so I tried to find an edge case where the absence of parentheses on a single number #define
causes issues, but I can't think of one.
Does such a case exist?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
是。预处理器串联运算符 (
##
) 将导致问题,例如:字符串化 (
#
) 也是如此。显然,这是一个极端情况,考虑到如何使用WIDTH
可能并不重要。尽管如此,关于预处理器还是需要记住一些事情。(添加第二个企鹅失败的原因是 C99 中预处理规则的一个微妙细节 - iirc 它失败是因为连接到两个非占位符预处理标记必须始终产生单个预处理标记 - 但是这个无关紧要,即使允许串联,它仍然会给出与不带括号的
#define
不同的结果!)。所有其他响应仅在从 C++ 扫描器的角度来看无关紧要的情况下才是正确的,因为事实上,数字是原子的。然而,根据我对问题的阅读,没有迹象表明只应考虑没有进一步预处理器扩展的情况,因此即使我完全同意其中包含的建议,其他答案也是错误的。
Yes. The preprocessor concatenation operator (
##
) will cause issues, for example:Same for stringization (
#
). Clearly this is a corner case and probably doesn't matter considering howWIDTH
will presumably be used. Still, it is something to keep in mind about the preprocessor.(The reason why adding the second penguin fails is a subtle detail of the preprocessing rules in C99 - iirc it fails because concatenating to two non-placeholder preprocessing tokens must always result in a single preprocessing token - but this is irrelevant, even if the concatenation was allowed it would still give a different result than the unbracketed
#define
!).All other responses are correct only insofar that it doesn't matter from the point of view of the C++ scanner because, indeed, a number is atomic. However, to my reading of the question there is no sign that only cases with no further preprocessor expansion should be considered, so the other responses are, even though I totally agree with the advice contained therein, wrong.
有时,您在编写代码时不必考虑当前的注意事项,而是考虑下次将要编辑的注意事项。
现在你的宏是一个整数。想象一下将来有人编辑它。假设他们不是你,而是一个不那么小心或更匆忙的人。括号的作用是提醒人们在其中进行任何修改。
这种思维在 C 语言中是一个好习惯。我个人以一种有些人可能会认为“多余”的风格编写代码,尤其是在错误处理方面。冗余是为了将来编辑的可维护性和可组合性。
Sometimes you have to write code not with the current caveats in mind, but with the ones of next time it is going to be edited.
Right now your macro is a single integer. Imagine someone editing it in the future. Let's say they are not you, but someone who is less careful or in more in a hurry. The parentheses are there to remind people to put any modifications within them.
This kind of thinking is a good habit in C. I personally write code in a style which some people might find "redundant", with things like this but especially with regards to error handling. Redundancy is for maintainability and composability of future editings.
作为 Blagovest Buyukliev 说:
但在涉及宏时,我建议遵循以下规则:
如果您想使用像宏这样的函数,请认真考虑以下 2 条规则:
为什么是规则 1。?
(为了保持操作顺序正确)
将扩展为:
为什么是规则 2.?
(为了确保副作用仅应用一次)
将扩展为:
As Blagovest Buyukliev said:
But I would recommend the following rules when it comes to macros:
If you want to use function like macros badly consider the following 2 rules:
Why rule 1.?
(To keep the order of the operations correct)
will expand to:
Why rule 2.?
(To ensure a side effect is only applied once)
will expand to:
当代码仅定义一个数字时,@Alexander Gessler很好地回答了这个问题。
然而,许多编码人员没有注意到以下内容中的一元运算符:
当代码使用使用运算符的
#define
时,将()
括起来可确保预期的结果数字结果和优先级。最后一行代码可能会编译给定的 C99 语义更改 @奥拉夫
When code defines only a number, @Alexander Gessler well answers the question.
Yet many coders do not notice the unary operators in the following:
When code uses a
#define
that employs an operator, enclosing()
insures expected numeric results and precedence.The last line of code may compile given C99 semantic changes @Olaf
每当定义由单个标记(仅一个操作数,无运算符)组成时,就不需要括号,因为单个标记(例如
100
)在词法分析和解析时是不可分割的原子。Whenever the define consists of a single token (one operand only, no operators), the parentheses are not needed because a single token (such as
100
) is an indivisible atom when lexing and parsing.由于
100
是单个标记,我怀疑您会发现括号很重要的极端情况(对于单个标记!)在我看来,这仍然是一个好习惯,因为当有多个标记时它们可能很重要涉及。
Since
100
is a single token, I doubt you'll find a corner case where the parentheses matter (for a single token!)It's still a good habit IMO, since they can matter when there are multiple tokens involved.
不会。
#define WIDTH 100
在任何情况下都不会产生明确或“令人惊讶”的扩展。这是因为它只能导致单个令牌被单个令牌替换。如您所知,当单个标记(例如
WIDTH
)导致多个标记(例如80 + 20
)时,就会发生宏混乱。据我推测,这是在替换中使用括号的唯一原因,正如我在第一段中探讨的那样,它不适用于此处。然而,抛开这个技术事实不谈,这可能仍然是一个很好的做法。它促进了习惯,并且如果该宏被修改为更复杂的东西,它也可以起到提醒作用。
No. There is no case where
#define WIDTH 100
can yield an unambiguous or "surprising" expansion. That's because it can only result in a single token being replaced by a single token.As you know, macro confusion ensues when a single token (e.g.
WIDTH
) results in multiple tokens (e.g.80 + 20
). As far as I can surmise, that's the only cause for the use of parentheses in substitutions and, as explored in my first paragraph, it doesn't apply here.However, this technical fact aside, it may still be a good practice. It promotes habit, and it also serves as a reminder if that macro ever gets modified to something more complex.
有时候,这是有充分理由的。
对于单个数字,没有充分的理由。
对于其他情况,正如您自己所表明的那样,这是有充分理由的。
有些人喜欢格外小心,并且总是使用括号(@aix 推荐这样做。我不这样做,但没有硬性答案)。
There's a good reason, sometimes.
For a single number, there's no good reason.
For other cases, as you have shown yourself, there is a good reason.
Some people prefer to be extra careful, and always use the parentheses (@aix recommends it. I don't, but there's no hard answer).
这当然不会造成伤害,而且这是一个好习惯。但对于数值计算而言,
(100)
和100
没有区别。It certainly won't hurt and it is a good habit. But there is no difference between
(100)
and100
for numerical calculations.