Ank*_*thD 48 c++ macros preprocessor-directive
我正在使用像C++这样的C++阅读它
#define max(a,b) (a > b ? a : b)
Run Code Online (Sandbox Code Playgroud)
可以导致"双重评估".有人能给我一个例子,说明何时进行双重评估以及为什么它会变坏?
PS:令人惊讶的是,除了在Clojure中的一个例子(我无法理解)之外,我在google搜索时找不到任何详细的解释.
Whi*_*TiM 70
想象一下你写的这个:
#define Max(a,b) (a < b ? b : a)
int x(){ turnLeft(); return 0; }
int y(){ turnRight(); return 1; }
Run Code Online (Sandbox Code Playgroud)
然后这样叫:
auto var = Max(x(), y());
Run Code Online (Sandbox Code Playgroud)
你知道turnRight()
会被执行两次吗?那个宏,Max
将扩展到:
auto var = (x() < y() ? y() : x());
Run Code Online (Sandbox Code Playgroud)
评估条件后x() < y()
,该程序然后采取之间所需的分支y() : x()
:在我们的例子中true
,它调用y()
的第二次.看到Live On Coliru.
简单地说,将表达式作为参数传递给类似函数的宏,Max
可能会对该表达式进行两次计算,因为表达式将在宏的参数中重复使用宏参数,在宏的定义中使用.请记住,宏由预处理器处理.
所以,底线是,不要使用宏来定义一个函数(在这种情况下实际上是一个表达式),因为你希望它是通用的,而它可以使用函数模板有效地完成
PS:C++有一个std::max
模板功能.
Fra*_*nck 24
a
并b
在宏定义中出现两次.因此,如果您将其与具有副作用的参数一起使用,则副作用将被执行两次.
max(++i, 4);
Run Code Online (Sandbox Code Playgroud)
如果i = 4
在通话之前将返回6 .由于它不是预期的行为,您应该更喜欢内联函数来替换像这样的宏max
.
sel*_*bie 20
请考虑以下表达式:
x = max(Foo(), Bar());
Run Code Online (Sandbox Code Playgroud)
在哪里Foo
和Bar
这样:
int Foo()
{
// do some complicated code that takes a long time
return result;
}
int Bar()
{
global_var++;
return global_var;
}
Run Code Online (Sandbox Code Playgroud)
然后在原始max
表达式中扩展如下:
Foo() > Bar() ? Foo() : Bar();
Run Code Online (Sandbox Code Playgroud)
无论哪种情况,Foo或Bar都要执行两次.从而花费超过必要的时间或改变程序状态超过预期的次数.在我的简单Bar
示例中,它不会一致地返回相同的值.
C和C++中的宏语言由"预处理"阶段的专用解析器处理; 翻译令牌,然后将输出馈送到解析器本身的输入流中.C或C++解析器本身无法识别#define
和#include
令牌.
这很重要,因为这意味着当一个宏被称为"扩展"时,它意味着字面意思.特定
#define MAX(A, B) (A > B ? A : B)
int i = 1, j = 2;
MAX(i, j);
Run Code Online (Sandbox Code Playgroud)
C++解析器看到的是什么
(i > j ? i : j);
Run Code Online (Sandbox Code Playgroud)
但是,如果我们使用更复杂的宏,则会发生相同的扩展:
MAX(i++, ++j);
Run Code Online (Sandbox Code Playgroud)
扩大到
(i++ > ++j ? i++ : ++j);
Run Code Online (Sandbox Code Playgroud)
如果我们传递了一个函数调用的东西:
MAX(f(), g());
Run Code Online (Sandbox Code Playgroud)
这将扩展到
(f() > g() ? f() : g());
Run Code Online (Sandbox Code Playgroud)
如果编译器/优化器可以证明f()
没有副作用,那么它会将其视为
auto fret = f();
auto gret = g();
(fret > gret) ? fret : gret;
Run Code Online (Sandbox Code Playgroud)
如果不能,则必须调用f()和g()两次,例如:
#include <iostream>
int f() { std::cout << "f()\n"; return 1; }
int g() { std::cout << "g()\n"; return 2; }
#define MAX(A, B) (A > B ? A : B)
int main() {
MAX(f(), g());
}
Run Code Online (Sandbox Code Playgroud)
现场演示:http://ideone.com/3JBAmF
类似地,如果我们调用一个extern
函数,优化器可能无法避免两次调用该函数.
归档时间: |
|
查看次数: |
5960 次 |
最近记录: |