在C中总是将define括在括号中,这有什么好的理由吗?

在C中总是将define括在括号中,这有什么好的理由吗?,c,c-preprocessor,parentheses,C,C Preprocessor,Parentheses,显然,有时#define语句必须有括号,如下所示: #define WIDTH 80+20 int a = WIDTH * 2; // expect a==200 but a==120 所以我总是用括号括起来,即使只是一个数字: #define WIDTH (100) 一个C新手问我为什么这样做,所以我试图找到一个边缘案例,即单个数字#define上没有括号会导致问题,但我想不出一个 这样的情况是否存在?既然100是一个单一的标记,我怀疑你会发现一个括号很重要的角落(对于单个标记!) 在我

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

#define WIDTH 80+20

int a = WIDTH * 2; // expect a==200 but a==120
所以我总是用括号括起来,即使只是一个数字:

#define WIDTH (100)
一个C新手问我为什么这样做,所以我试图找到一个边缘案例,即单个数字
#define
上没有括号会导致问题,但我想不出一个


这样的情况是否存在?

既然
100
是一个单一的标记,我怀疑你会发现一个括号很重要的角落(对于单个标记!)


在我看来,这仍然是一个好习惯,因为当涉及多个令牌时,它们可能很重要。

每当定义由单个令牌组成时(仅一个操作数,没有运算符),不需要括号,因为只有一个令牌(例如
100
)在词法分析和解析时是一个不可分割的原子。

否。
#define WIDTH 100
在任何情况下都不会产生明确或“令人惊讶”的扩展。这是因为它只能导致单个令牌被单个令牌替换

如您所知,当单个令牌(例如
宽度
)导致多个令牌(例如
80+20
)时,宏混乱就会随之发生。据我推测,这是在替换中使用括号的唯一原因,正如我在第一段中所探讨的,它不适用于这里


然而,撇开这一技术事实不谈,这可能仍然是一种良好的做法。它促进了习惯,而且如果宏被修改成更复杂的东西,它也可以作为一个提醒。

有时候有一个很好的理由

对于一个数字,没有什么好的理由

对于其他情况,正如你所展示的,有一个很好的理由


有些人喜欢格外小心,总是使用括号(@aix建议使用括号。我不这样做,但没有确切的答案)。

这当然不会有什么害处,而且是一个好习惯。但是对于数值计算,
(100)
100
之间没有区别。

有时,您编写代码时必须考虑下一次编辑时的注意事项,而不是当前的注意事项

现在,宏是一个单整数。想象一下将来有人在编辑它。假设他们不是你,而是一个不太小心或比较匆忙的人。括号用来提醒人们在括号内进行修改


这种想法在C语言中是一个好习惯。我个人编写代码的风格可能会让一些人觉得“多余”,比如这样,但特别是在错误处理方面。冗余是为了将来编辑的可维护性和可组合性。

。预处理器串联运算符(
##
)将导致问题,例如:

#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
,这可能无关紧要。尽管如此,预处理器还是需要记住的

(添加第二个penguin失败的原因是C99-iirc中预处理规则的一个细微细节。它失败是因为连接到两个非占位符预处理标记必须始终导致一个预处理标记-但这与此无关,即使允许连接,它仍然会给出与unb不同的结果敲打
#定义
!)

所有的其他响应都是正确的,只是从C++扫描器的角度来看,这并不重要,因为实际上,原子是原子的。然而,在我阅读的问题中,没有迹象表明只有考虑没有进一步的预处理器扩展的情况,所以其他的反应是,即使我完全同意A。其中包含的dvice错误。

如前所述:

define由单个标记(仅一个操作数,无运算符)组成,不需要括号,因为在词法分析和解析时单个标记(如100)是不可分割的原子

但对于宏,我推荐以下规则:

  • 避免使用类似宏的函数@see Lundin的注释
  • <强>如果您想使用函数类宏,请仔细考虑以下2个规则:>/P>

  • 宏中的参数始终使用括号
  • 只能使用宏参数一次
  • 为什么是规则1。? (保持操作顺序正确)

    将扩展到:

    int a = (2+3*2+3);
    
    int a = i++ * i++;
    
    为什么是规则2。? (确保副作用只应用一次)

    将扩展到:

    int a = (2+3*2+3);
    
    int a = i++ * i++;
    

    当代码只定义一个数字时,我们很好地回答了这个问题

    然而,许多编码人员没有注意到以下一元运算符:

    #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语义更改

    如果有人知道非平凡的宏需要括号,他会在更改时添加括号。如果不知道,无论你做什么,他都会造成混乱。因此我反对添加显然不需要的括号。但这是一个意见问题。我不同意-你不应该使用括号让非程序员在将来维护您的代码。在宏表达式周围加括号是一件很基本的事情,您应该能够假设每个C程序员都知道它。否则,通过使用相同的参数,您应该在所有内容周围加括号:
    int x=y+z;
    (不是宏)那么,是否应该用同样有缺陷的逻辑编写为
    intx=(y+z);
    ,以防一个紧张的非程序员将来会维护代码,提醒他们运算符优先的危险。好吧,伙计们,那么我不同意你们的不同意见。:-)特别是@Lundin的评论,我说的不是非程序员,而是糟糕或不小心的程序员——这似乎是错误的