使用宏进行符号计算
Sign computation with a macro
以下表达式计算的究竟是什么?
#define SIGN(x) ((x < 0) ? -1 : (x > 0))
如果 x 为零、小于零、大于零,结果是什么?
我想我知道答案,但我想检查清楚...
谢谢
编辑:添加了缺少的括号
编辑:更多信息 here
它的作用与您可能认为的作用完全相同,-1
表示负数,0
表示零,1
表示正数。
但是,您通常应该避免使用 function-like 宏,因为它们 不会 执行您期望的操作,例如,如果您尝试计算 SIGN(value++)
。由于它们是简单的文本替换,因此将解析为:
((value++ < 0) ? -1 : (value++ > 0)
你最好只使用 real 函数并让编译器在认为值得时内联它们。您还可以建议编译器使用 inline
关键字内联它,但请记住它 是 一个建议。
那个宏有一个杂散的括号。
它看起来像是 signum 函数的实现,returns -1、1 或 0 取决于参数的值。
为了安全起见,写C++代码,慎重
用模板替换宏,类似于
template <class T>
int SIGN( T x )
{
return (x < T(0)) ? -1 : (x > T(0));
}
首先比较的是三元运算符的参数?:。如果表达式的计算结果为 true,即 x 小于 0,则三元将 return -1,否则它将 return x > T(0) 的结果。
如果 x 等于 0,则该表达式将计算为 0,否则将计算为 1。
请注意,我的实现并不理想,您可以在 SO 的其他地方找到更好的实现。
替代表达式可以是:
return (T(0)<x) - (T(0)>x);
对于实现某些 CPU 指令的平台,这可能更有效
首先,宏不计算任何东西。它被代入源代码、扩展,并编译生成的文本。结果文本是什么,取决于您使用宏的方式,尤其是您提供的参数。
其次,该宏缺少一个右括号,因此它可能不会为您提供一个有意义的表达式进行编译。
第三,即使你添加了缺少的括号:
#define SIGN(x) ((x < 0) ? -1 : (x > 0))
如果您以 non-simplest 的方式使用宏,您可能会得到意想不到的结果。例如,
SIGN(a ^ b)
会导致
((a ^ b < 0) ? -1 : (a ^ b > 0))
在 C 和 C++ 中解释为
((a ^ (b < 0)) ? -1 : (a ^ (b > 0)))
这肯定不是我们想要的。
您应该添加括号以避免不必要的运算符绑定 – for:
#define SIGN(x) (((x) < 0) ? -1 : ((x) > 0))
以上示例将产生一个合理的表达式
(((a ^ b) < 0) ? -1 : ((a ^ b) > 0))
但这仍然不能保护您免受 plus-plus 或 minus-minus 运算符的不必要的双重 increment/decrement 或函数的双重执行,以防表达式替换为 x
包含函数调用。
如果您仅将它用于值而不是表达式,该宏将产生 -1、0、1,否则您可能会遇到严重的问题。棘手的部分是 (x>0)。让我们阅读标准:
5.9 Relational operators [expr.rel]
The operators < (less than), > (greater than), <= (less than or equal
to), and >= (greater than or equal to) all yield false or true. The
type of the result is bool.
和
3.9.1 Fundamental types [basic.fundamental]
Values of type bool are either true or false. Values of type bool participate in integral promotions (4.5).
因此 x>0 是 true
或 false
。
4.5 Integral promotions [conv.prom]
A prvalue of type bool can be converted to a prvalue of type int, with false becoming zero and true becoming one.
并晋升为 1
或 0
(分别)。
以下表达式计算的究竟是什么?
#define SIGN(x) ((x < 0) ? -1 : (x > 0))
如果 x 为零、小于零、大于零,结果是什么? 我想我知道答案,但我想检查清楚...
谢谢
编辑:添加了缺少的括号 编辑:更多信息 here
它的作用与您可能认为的作用完全相同,-1
表示负数,0
表示零,1
表示正数。
但是,您通常应该避免使用 function-like 宏,因为它们 不会 执行您期望的操作,例如,如果您尝试计算 SIGN(value++)
。由于它们是简单的文本替换,因此将解析为:
((value++ < 0) ? -1 : (value++ > 0)
你最好只使用 real 函数并让编译器在认为值得时内联它们。您还可以建议编译器使用 inline
关键字内联它,但请记住它 是 一个建议。
那个宏有一个杂散的括号。 它看起来像是 signum 函数的实现,returns -1、1 或 0 取决于参数的值。
为了安全起见,写C++代码,慎重 用模板替换宏,类似于
template <class T>
int SIGN( T x )
{
return (x < T(0)) ? -1 : (x > T(0));
}
首先比较的是三元运算符的参数?:。如果表达式的计算结果为 true,即 x 小于 0,则三元将 return -1,否则它将 return x > T(0) 的结果。 如果 x 等于 0,则该表达式将计算为 0,否则将计算为 1。
请注意,我的实现并不理想,您可以在 SO 的其他地方找到更好的实现。 替代表达式可以是:
return (T(0)<x) - (T(0)>x);
对于实现某些 CPU 指令的平台,这可能更有效
首先,宏不计算任何东西。它被代入源代码、扩展,并编译生成的文本。结果文本是什么,取决于您使用宏的方式,尤其是您提供的参数。
其次,该宏缺少一个右括号,因此它可能不会为您提供一个有意义的表达式进行编译。
第三,即使你添加了缺少的括号:
#define SIGN(x) ((x < 0) ? -1 : (x > 0))
如果您以 non-simplest 的方式使用宏,您可能会得到意想不到的结果。例如,
SIGN(a ^ b)
会导致
((a ^ b < 0) ? -1 : (a ^ b > 0))
在 C 和 C++ 中解释为
((a ^ (b < 0)) ? -1 : (a ^ (b > 0)))
这肯定不是我们想要的。
您应该添加括号以避免不必要的运算符绑定 – for:
#define SIGN(x) (((x) < 0) ? -1 : ((x) > 0))
以上示例将产生一个合理的表达式
(((a ^ b) < 0) ? -1 : ((a ^ b) > 0))
但这仍然不能保护您免受 plus-plus 或 minus-minus 运算符的不必要的双重 increment/decrement 或函数的双重执行,以防表达式替换为 x
包含函数调用。
如果您仅将它用于值而不是表达式,该宏将产生 -1、0、1,否则您可能会遇到严重的问题。棘手的部分是 (x>0)。让我们阅读标准:
5.9 Relational operators [expr.rel]
The operators < (less than), > (greater than), <= (less than or equal to), and >= (greater than or equal to) all yield false or true. The type of the result is bool.
和
3.9.1 Fundamental types [basic.fundamental]
Values of type bool are either true or false. Values of type bool participate in integral promotions (4.5).
因此 x>0 是 true
或 false
。
4.5 Integral promotions [conv.prom]
A prvalue of type bool can be converted to a prvalue of type int, with false becoming zero and true becoming one.
并晋升为 1
或 0
(分别)。