C 为什么宏中有这么多括号?

C 为什么宏中有这么多括号?,c,com,macros,c-preprocessor,C,Com,Macros,C Preprocessor,Windows SDK功能宏: #define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0) -----------------------^-------------^----- 很明显,和其他宏一样,有括号可以确保编译器正确解释意图 我不明白为什么(HRESULT)(hr)(我用^字符标记了它们)周围有括号hr用括号括起来,这样一些复杂的构造就可以出现了,HRESULT用括号括起来形成一个C风格的强制转换,然后整个=构造也用括号括起来,那么为什么在(HRE

Windows SDK功能宏:

#define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0)
-----------------------^-------------^-----
很明显,和其他宏一样,有括号可以确保编译器正确解释意图


我不明白为什么
(HRESULT)(hr)
(我用
^
字符标记了它们)周围有括号
hr
用括号括起来,这样一些复杂的构造就可以出现了,
HRESULT
用括号括起来形成一个C风格的强制转换,然后整个
=
构造也用括号括起来,那么为什么在
(HRESULT)(hr)
周围加上一对括号?

大括号确保元素的顺序正确。您不希望编译器执行以下操作:

  • (hr)>=0

  • 将结果转换为1。至
    HRESULT


  • 相反,您只想将
    (hr)
    表达式转换为
    HRESULT
    ,然后将其与
    0
    进行比较,这是为了确保在进行比较之前将hr转换为HRESULT,而不是将HRESULT(hr>=0)。

    确保将从(hr)展开的表达式转换为HRESULT,然后与0进行比较。

    C标准将强制转换置于比比较更高的优先级,因此编译器不需要使用参数


    但是,人们阅读宏定义,并将其放入宏定义中会使优先级变得明确,因此阅读宏定义的人很明显,它是比较((HRESULT)hr)与零的结果,而不是在不考虑优先级的情况下抛出比较结果。

    额外的括号不会改变含义,但它们确实明确了优先顺序。如果没有它们,一个不知道所有优先规则的读者将不得不理解这个表达式的含义


    为了澄清,我只是指问题中标记的cast表达式周围的括号。其它的是必要的(除非宏只针对C++而不是C,在这种情况下,你可以改变<代码>(HREST)(HR)到<代码> HESREST(HR)。

    < P>简短回答:谁知道MS开发者在想什么。但是,围绕hr的括号显然是必要的,因为hr可能是由多个操作数组成的表达式。在我看来((HRESULT)(hr))周围的括号是不必要的。这可能是出于一个谨慎的习惯:在使用预处理器时,括号太多比太少要好。

    这是为了解决宏的缺点-它们只是一个文本替换

    想象一下下面的宏

    #define DOUBLE(x) x*2
    
    int v = DOUBLE(1+1); // == 1+1*2 == 3. Did you expect 4?
    
    因此,宏的经验法则是:

    • 只有在没有其他方法解决问题时才使用它们
    • 将每个参数包装在paranethes中(以避免上述问题)
    • 将整个表达式用偏执语句包装(以避免其他类似问题)
    • 使每个参数只出现一次(以避免出现副作用问题)
    因此,更好的宏应该是:

    #定义双(x)((x)*2)

    你就快到了,在你的例子中剩下的偏执是由于演员阵容


    因此,我们可以批评两点:

    Q:为什么它是宏而不是内联函数?
    A:向后兼容性。C没有内联函数(或者至少没有),将函数用于可能成千上万的此类声明会使当时的大多数编译器崩溃

    Q:这个特定宏真的需要这些偏执吗?
    我不知道。我可能需要半个小时或更长的时间来正式证明(或反驳)没有合理的参数和“调用”环境,在这些环境中会产生意外的影响。我宁愿遵循上面提到的合理指导方针,继续编码

    作者就是愚蠢。所有额外的括号(围绕cast)都会使可视化解析变得更加困难。任何认为比较可能比强制转换具有更高优先级的人都需要在编码之前学习语言的基础知识。。。更不用说只需要一些常识。

    优先规则确保;括号只是让读者明白情况就是这样。-1,不是真的。请参阅我答复中的示例:含义可能会因传递的参数而改变,因为宏是jsut文本替换。@彼得森:在这种情况下,参数用括号括起来,因此任何有效表达式的含义都是相同的,无论强制转换表达式周围是否有额外的括号。宏当然会有陷阱,但这一个不会。除非你能提供一个能打破它的论点的例子。你是对的,迈克,我忽略了他文章下面的“有趣的线条”。但是,除非您进行编辑,否则无法撤销-1。您的第一个示例缺少
    DOUBLE
    的定义……这是一个很好的一般性建议,但与问题无关;succeed的参数和整个表达式一样用括号括起来。问题是关于演员表达中多余的偏执。检查我评论的时间和编辑历史中的时间;埃德蒙帮你修好了。:-)很抱歉我的编辑过于迂腐,但每次我在主页上看到这个问题标题时,我都会感到困扰…@AakashM:既然我不是英语母语人士,我不得不问:“大括号”和“括号”有什么区别?我到处都能看到像“你需要在你的宏中正确地设置参数”这样的短语。为什么“大括号”这个词在这里不合适?@sharptooth:“大括号”通常,尽管不总是,意思是
    {}
    ,有时被称为“花括号”。“括号”通常指
    ()
    ,有时称为“圆括号”。“方括号”有时用于表示
    []
    ,有时称为“方括号”和“尖括号”。这三个术语经常互换使用。英语不如C++精确。