显然,有时候#define
语句必须有括号,如下所示:
#define WIDTH 80+20
int a = WIDTH * 2; // expect a==200 but a==120
所以我总是括号,即使它只是一个数字:
#define WIDTH (100)
C的新人问我为什么要这样做,所以我试图找到一个边缘情况,其中单个数字#define
上没有括号会导致问题,但我想不出一个。
是否存在这种情况?
答案 0 :(得分:37)
是即可。预处理程序连接运算符(##
)将导致问题,例如:
#define _add_penguin(a) penguin ## a
#define add_penguin(a) _add_penguin(a)
#define WIDTH (100)
#define HEIGHT 200
add_penguin(HEIGHT) // expands to penguin200
add_penguin(WIDTH) // error, cannot concatenate penguin and (100)
字符串化(#
)相同。显然,这是一个极端情况,考虑如何使用WIDTH
可能无关紧要。尽管如此,仍需要牢记预处理器。
(添加第二只企鹅失败的原因是C99中预处理规则的一个细微细节 - iirc 它失败了,因为连接到两个非占位符预处理令牌必须始终产生一个预处理令牌 - 但这是无关紧要的,即使连接被允许,它仍然会得到与未括号#define
不同的结果!)。
所有其他响应只有从C ++扫描器的角度来看无关紧要,因为实际上,数字是原子的。但是,在我阅读这个问题时,并没有迹象表明只考虑没有进一步预处理器扩展的案例,所以其他答案即使我完全同意其中包含的建议也是错误的。
答案 1 :(得分:26)
有时候你必须编写代码而不是考虑当前的警告,但是下次编辑时需要注意。
现在你的宏是一个整数。想象一下将来有人编辑它。让我们说他们不是你,而是一个不那么小心或更匆忙的人。括号用于提醒他们在括号中进行任何修改。
这种想法是C中的一个好习惯。我个人用一种人们可能会发现“多余”的风格编写代码,这类似的东西,尤其是错误处理方面。冗余用于未来编辑的可维护性和可组合性。
答案 2 :(得分:8)
每当define包含单个标记(仅一个操作数,没有运算符)时,就不需要括号,因为单个标记(例如100
)在进行lexing和解析时是不可分割的原子。
答案 3 :(得分:8)
正如Blagovest Buyukliev所说:
define由单个标记组成(仅一个操作数,没有运算符),不需要括号,因为单个标记(例如100)在进行lexing和解析时是不可分割的原子。
但在宏方面我会建议以下规则:
如果您想使用像宏一样的功能,请严格考虑以下两条规则:
为什么要遵守规则1.? (为了保持操作的顺序正确)
#define quad(x) (x*x)
int a = quad(2+3);
将扩展为:
int a = (2+3*2+3);
为什么要统治2? (确保副作用仅应用一次)
#define quad(x) (x*x)
int i = 1;
int a = quad(i++);
将扩展为:
int a = i++ * i++;
答案 4 :(得分:6)
由于100
是一个令牌,我怀疑你会发现一个角落的情况,括号很重要(对于一个令牌!)
这仍然是IMO的一个好习惯,因为当涉及多个令牌时它们会很重要。
答案 5 :(得分:6)
没有。没有#define WIDTH 100
可以产生明确或“令人惊讶”扩展的情况。那是因为它只会导致单个令牌被单个令牌替换。
如您所知,当单个令牌(例如WIDTH
)导致多个令牌(例如80 + 20
)时,会出现宏观混淆。据我所知,这是唯一的原因,在替换中使用括号,并且如我的第一段所述,它不适用于此。
然而,抛开这个技术事实,它仍然是一个好习惯。它促进了习惯,如果宏被修改为更复杂的东西,它也可以作为提醒。
答案 6 :(得分:3)
有时候有充分的理由。
对于一个号码,没有充分的理由。
对于其他情况,正如您自己展示的那样,有充分的理由。
有些人更喜欢格外小心,并且总是使用括号(@aix推荐它。我没有,但没有硬答案)。
答案 7 :(得分:2)
它肯定不会受到伤害,这是一个好习惯。但是(100)
和100
之间的数值计算没有区别。
答案 8 :(得分:2)
当代码只定义一个数字时,@Alexander Gessler很好地回答了问题。
然而,许多程序员在下面没有注意到一元运算符:
#define TEMPERATURE1M (-1)
#define TEMPERATURE1P (+1)
当代码使用使用运算符的#define
时,封闭()
可确保预期的数字结果和优先级。
#define TEMPERATURE_WITH (-1)
#define TEMPERATURE_WITHOUT -1
// Consider how these will compile
int w = 10-TEMPERATURE_WITH;
int wo = 10-TEMPERATURE_WITHOUT; // May not compile
最后一行代码可以编译给定C99语义更改@Olaf