用宏签名计算

时间:2018-03-22 11:28:39

标签: algorithm c++11 macros computation

以下表达式究竟计算了什么?

#define SIGN(x) ((x < 0) ? -1 : (x > 0))

如果x为零,小于零,大于零,会产生什么? 我想我知道答案,但我想检查清楚......

谢谢

编辑:添加了缺少的括号 编辑:更多信息here

4 个答案:

答案 0 :(得分:2)

它完全符合你的想法,负数为-1,零为0,正数为1

但是,您通常应该避免使用类似函数的宏,因为例如,如果您尝试计算SIGN(value++),它们会执行您期望的操作。由于它们是简单的文本替换,因此可以解决:

((value++ < 0) ? -1 : (value++ > 0)

你只需使用真正的函数,并让编译器内联它们,如果它决定它是值得的,那就更好了。您还可以使用inline关键字向编译器建议内联它,但请记住 是一个建议。

答案 1 :(得分:2)

首先,宏不计算任何东西。它被替换为源代码,扩展,并生成结果文本。生成的文本取决于您使用宏的方式,尤其取决于您给出的参数。

其次,宏缺少一个结束语,所以它可能不会给你一个有意义的表达式来编译。

第三,即使你添加缺乏的paren:

#define SIGN(x) ((x < 0) ? -1 : (x > 0))

如果以非最简单的方式使用宏,则可能会出现意外结果。例如,

SIGN(a ^ b)

会导致

((a ^ b < 0) ? -1 : (a ^ b > 0))

在C和C ++中解释为

((a ^ (b < 0)) ? -1 : (a ^ (b > 0)))

当然我们打算做什么。

您应该添加括号以避免不需要的运算符绑定 - 对于:

#define SIGN(x) (((x) < 0) ? -1 : ((x) > 0))

上面的例子将产生一个明智的表达

(((a ^ b) < 0) ? -1 : ((a ^ b) > 0))

但是,如果替换为x的表达式包含函数调用,则在加号或减号运算符的情况下仍然不能保护您免受不必要的双增/减,或者双重执行函数。

答案 2 :(得分:1)

那个宏有一个假的括号。 它看起来像是signum函数的一个实现,它根据参数的值返回-1,1或0。

为了安全起见并编写C ++代码,这是谨慎的 用模板替换宏,类似于

template <class T>
int SIGN( T x )
{
 return (x < T(0)) ? -1 : (x > T(0));
}

第一个比较是trenary运算符的参数?:。如果表达式求值为真,则三元将返回-1,即x小于0,否则它将返回x> 1的结果。 T(0)。 如果x等于0,该表达式将计算为0,否则将评估为1。

请注意,我的实现并不理想,你可以在其他地方找到更好的实现。 另一种表达方式可以是:

return (T(0)<x) - (T(0)>x);

对于实现某些CPU指令的平台,这可能更有效

答案 3 :(得分:0)

如果仅将值与值一起使用而不是宏将生成-1,0,1的表达式,否则可能会出现严重问题。棘手的部分是(x> 0)。让我们阅读标准:

  

5.9关系运算符[expr.rel]

     

运营商&lt; (小于),&gt; (大于),&lt; =(小于或等于   to)和&gt; =(大于或等于)所有产生false或true。该   结果的类型是bool。

  

3.9.1基本类型[basic.fundamental]

     

bool类型的值为true或false。 bool类型的值参与整体促销(4.5)。

因此x> 0是truefalse

  

4.5整体促销[conv.prom]

     

bool类型的prvalue可以转换为int类型的prvalue,false变为零,true变为1。

并分别提升为10