是否有充分的理由始终在C中用括号括起一个定义?

时间:2012-01-31 14:46:02

标签: c c-preprocessor parentheses

显然,有时候#define语句必须有括号,如下所示:

#define WIDTH 80+20

int a = WIDTH * 2; // expect a==200 but a==120

所以我总是括号,即使它只是一个数字:

#define WIDTH (100)

C的新人问我为什么要这样做,所以我试图找到一个边缘情况,其中单个数字#define上没有括号会导致问题,但我想不出一个。

是否存在这种情况?

9 个答案:

答案 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. 避免使用类似宏的功能@see Lundin的评论。
  2. 如果您想使用像宏一样的功能,请严格考虑以下两条规则:

    1. 始终在宏中使用括号作为参数
    2. 只使用一次宏参数
    3. 为什么要遵守规则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