【问题标题】:Why so many parentheses in SUCCEEDED macro?为什么 SUCCEEDED 宏中有这么多括号?
【发布时间】:2010-06-25 12:36:50
【问题描述】:

Windows SDK 具有 SUCCEEDED 宏:

#define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0)
-----------------------^-------------^-----

显然,与其他宏一样,括号可确保编译器正确解释意图。

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

【问题讨论】:

  • 对过于迂腐的编辑表示歉意,但每次我在主页上看到问题标题时,我都感到很烦......
  • @AakashM:由于我的母语不是英语,所以我不得不问:“大括号”和“括号”有什么区别?我到处都看到像“你需要在你的宏中正确地支持参数”这样的短语。为什么“大括号”这个词在这里不合适?
  • @sharptooth:“大括号”通常(但并非总是)表示{},有时也称为“大括号”。 “括号”通常表示(),有时也称为“圆括号”。 “方括号”有时用于表示[]<>,有时也称为“方括号”和“尖括号”。这三个术语通常可以互换使用。英语不如 C++ 精确。
  • @sharptooth:在一般英语使用中,这些是括号:(),这些是括号:[],这些是大括号:{}。 “括号”的使用有一定的灵活性,但我不记得以前看到过“大括号”的意思是“括号”。
  • @sharptooth 另见catb.org/jargon/html/A/ASCII.html ;基本上,正如@Mike Seymour 所说,但对我个人而言,将() 称为“大括号”的互换性太过分了:) 我通常会原谅“括号”,因为这是英语(和数学)所说的,但如果我们不能迂腐的我们可以在哪里......

标签: c com macros c-preprocessor


【解决方案1】:

C 标准将强制转换置于比比较更高的优先级,因此编译器不需要括号。

但是,人们阅读宏定义,并将它们放入其中使优先级明确,因此阅读它的人很明显,这是将 ((HRESULT)hr) 与零进行比较的结果,而不是强制转换的结果无需考虑优先级即可进行比较。

【讨论】:

    【解决方案2】:

    额外的括号不会改变含义,但它们确实明确了优先级。没有它们,不了解所有优先规则的读者将不得不弄清楚表达式的含义。

    为澄清起见,我仅指问题中标记的强制转换表达式周围的括号。其他的都是必需的(除非该宏仅用于 C++ 而不是 C,在这种情况下您可以将 (HRESULT)(hr) 更改为 HRESULT(hr))。

    【讨论】:

    • -1,不正确。请参阅我回复中的示例:含义可能会根据传递的参数而改变,因为宏是 jsut 文本替换。
    • @peterchen:在这种情况下,参数用括号括起来,因此任何有效表达式的含义都是相同的,无论强制转换表达式周围有或没有任何额外的括号。宏当然有陷阱,但不是这个。除非你能提供一个会破坏它的论点的例子。
    • 你说得对,迈克,我忽略了他文字下方的“有趣的一行”。但是,除非您进行编辑,否则无法撤销 -1。
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      这是为了应对宏的缺点——它们只是一个文本替换!

      想象下面的宏

      #define DOUBLE(x) x*2
      
      int v = DOUBLE(1+1); // == 1+1*2 == 3. Did you expect 4?
      

      所以宏的经验法则是:

      • 只有在没有其他方法可以解决您的问题时才使用它们
      • 将每个参数都用括号括起来(以避免上述问题)
      • 将整个表达式用括号括起来(以避免其他类似问题)
      • 让每个参数只出现一次(以避免副作用问题)

      所以,一个更好的宏应该是:

      #define DOUBLE(x) ((x)*2)

      你快到了,你的例子中剩下的括号是由于演员表。


      所以我们可以批评两点:

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

      问:这个特定的宏真的需要括号吗? 答:我不知道。我可能需要半小时或更长时间才能正式证明(或反证)没有合理的参数和“调用”环境,这会产生意想不到的影响。我宁愿遵循上述明智的指导方针,然后继续编码。

      【讨论】:

      • 您的第一个示例缺少DOUBLE 的定义...
      • 这是很好的一般建议,但与问题无关; SUCCEEDED 的参数应该用括号括起来,整个表达式也是如此。问题是围绕演员表表达的多余的括号。
      • 查看我评论的时间和编辑历史中的时间;埃德蒙为你修好了。 :-)
      【解决方案5】:

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

      【讨论】:

        【解决方案6】:

        大括号确保元素按正确的顺序排列。您不希望编译器这样做:

        1. (hr) >= 0

        2. 将1.的结果转换为HRESULT

        您只想将(hr) 表达式转换为HRESULT,然后将其与0 进行比较。

        【讨论】:

        • 当然,但这就是 C 和 C++ 运算符优先级的作用,大多数人都意识到这一点。
        【解决方案7】:

        这是为了确保在比较之前将hr转换为HRESULT,而不是HRESULT(hr >= 0)。

        【讨论】:

        • 优先规则确保;括号只是让读者清楚地知道情况就是这样。
        【解决方案8】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-10-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-08-05
          • 1970-01-01
          相关资源
          最近更新 更多