C++宏忽略之后的内容

C++ macro ignoring what's after

本文关键字:之后 C++      更新时间:2023-10-16

我正在处理一个动态编程问题,决定不使用std::max函数,因为我认为宏会更快(在堆栈上不推参数,而不是模板化(。

但它并没有像预期的那样发挥作用。我已经隔离了这个问题,它看起来像这样:

#include <iostream>
#define maxi(a, b) (a <= b)? b : a
using namespace std;
int main()
{
int a = 0, b = 0, c = 0;
c =  maxi(a, b) + 1;
cout << c;
return 0;
}

虽然它确实返回了最大值,但似乎忽略了之后添加的1。在这个例子中,c的值最终是0,而我希望它是1。为什么?

宏替换后的代码如下所示。你现在明白错在哪里了吗?

// ...
int a = 0, b = 0, c = 0;
c =  (a <= b)? b : a + 1;

要快速修复,只需将所有宏作为#define maxi(a, b) ((a <= b)? b : a)放入additional((中即可。在编写任何宏时,这都是一个很好的做法。这种变化将导致以下代码变化:

// ...
int a = 0, b = 0, c = 0;
c =  ((a <= b)? b : a) + 1;

请记住,如果你的a和b参数更复杂,你会遇到类似的问题,因此为了使宏更容易出错,你也应该把所有参数放在单独的((中,就像#define maxi(a, b) (((a) <= (b))? (b) : (a))中一样

您的宏缺少多个圆括号,以避免它在某些表达式中中断,例如,在您显示的情况下,它将被替换为:

c =  (a <= b)? b : a + 1;

如您所见,您将返回CCD_ 3或CCD_。这不是你想要的。

您需要将宏写入

#define maxi(a, b) (((a) <= (b)) ? (b) : (a))

以避免争论中出现此类和类似的问题。

这在任何方面都不比std::max更有效。编译器执行内联小函数,内联后,使用std::max的函数看起来与maxi被替换时几乎相同。无论是在寄存器中还是在堆栈上,都不会传递函数参数。

Btw。是否模板化的函数对其性能特性没有影响。所以我不知道你为什么在问题中提到这一点。

正如你所看到的,宏很难使用,所以没有理由使用它们。

相反,在某些情况下,您的宏会更糟,例如:

maxi(f(a), f(b))

其中f是某种函数,将(大致(替代

(f(a) <= f(b))? f(b) : f(a);

这意味着f将总是被评估三次,用于比较中的前两次调用,以及一次用于所选分支。

另一方面,std::max(f(a), f(b))仅评估f两次。

这意味着宏不仅需要更多的时间,如果函数调用有副作用,它还可能产生意想不到的效果。

C++预处理器在编译前替换单词所以你的线路变成了-

c = (a<=b) ? b : a +1;

a>b时只增加a

对于这两种情况,代码#define段通常应该用大括号卷曲,以消除歧义-

#define maxi(a, b) ((a <= b)? b : a)

这将使预处理的生产线成为

c = ((a<=b) ? b : a) +1;

这将产生正确的输出。

我正在处理一个动态编程问题,决定不使用std::max函数,因为我认为宏会更快(不在堆栈上推送参数,而不是模板化(。

你的决定不是很明智。任何半成品的优化编译器都会优化出std::max中的函数调用。宏只会毒害他们所涉及的任何东西,从你的例子中可以看出。


要查看宏有什么问题,请告诉编译器向您显示源代码的预处理版本(GCC的-E标志(:

此:

#define maxi(a, b) (a <= b)? b : a
int main()
{
int a = 0, b = 0, c = 0;
c =  maxi(a, b) + 1;
}

变成这样:

int main()
{
int a = 0, b = 0, c = 0;
c = (a <= b)? b : a + 1;
}

这不是你想要的。以下是"修复":

#define maxi(a, b) (((a) <= (b))? (b) : (a))

这真的不是一个真正的解决方案。考虑一下像maxi(++a, b)这样的东西。这扩展到CCD_ 18,可能使CCD_ 19增加两倍。这绝对不是预期的行为。