为什么在SUCCEEDED宏中有这么多括号?

Windows SDK具有SUCCEEDED宏:

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

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

我没有得到的是为什么周围有括号(HRESULT)(hr) (我用^字符标记它们)。 hr括号括起来,以便有一些复杂的构造可以存在, HRESULT被括号括起来形成一个C风格的HRESULT转换,然后整个>=构造也被括号括起来,那么为什么额外的一对括号(HRESULT)(hr)呢?

C标准使得演员的优先级高于比较,因此编译器不需要parens。

然而,人们阅读宏定义,并将它们放入使得优先级明确,因此对于阅读它的人来说显而易见的是,它是比较((HRESULT)hr)与零的结果,而不是在没有比较结果的情况下不得不考虑优先权。

额外的括号不会改变含义,但它们确实使优先级显式化。 如果没有它们,那些不了解所有优先规则的读者就必须弄清楚表达式的含义。

为了澄清,我只是指在演员表达式周围的括号,如问题中所标记的那样。 其他是必要的(除非宏仅用于C ++而不是C,在这种情况下,您可以将(HRESULT)(hr)更改为HRESULT(hr) )。

简短的回答:谁知道MS开发人员的想法。 但是,hr附近的括号显然是必要的,因为hr可以是由多个操作数组成的表达式。 据我所知,围绕((HRESULT)(hr))的括号是不必要的。 这可能只是出于一种警示习惯:在使用预处理器时,最好有太多括号而不是太少。

这是为了应对宏观缺陷 – 它们只是一个文本替代品!

想象下面的宏

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

所以宏的经验法则是:

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

所以,一个更好的宏将是:

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

你几乎就在那里,在你的例子中剩下的parantheses是由于演员。


所以我们可以批评两点:

问:为什么它是宏,而不是内联函数?
答:向后兼容性。 C没有内联函数(或者至少没有),使用大约数千个此类声明的函数会导致当时大多数编译器失效。

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

作者只是愚蠢。 所有额外的括号(在演员周围)都会使视觉解析变得更难。 任何认为比较可能具有比铸造更高优先级的人需要在编码之前学习语言的基础知识……更不用说只是获得一些常识。

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

  1. (hr) >= 0

  2. 将结果转换为HRESULT

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

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

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