C++宏忽略之后的内容
C++ macro ignoring what's after
我正在处理一个动态编程问题,决定不使用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增加两倍。这绝对不是预期的行为。
- 为什么在popback()操作之后,它仍然打印完整的矢量
- 在类定义之后定义一个私有方法
- 在循环C++中指定字符串之后,不会打印该字符串
- C++宏忽略之后的内容
- 要与"if constexpr"一起使用的编译时消息(在预处理器之后)
- strncpy之后的char数组的错误行为
- 计算十进制 c++ 之后的数字
- "x += x--"之后的 x 是什么?
- 类的前向声明之后的类成员函数定义,在类声明之前
- 为什么将双精度转换为 int 似乎在第 16 位数字之后将其四舍五入?
- execlp() 在 fork() 之后无法正常工作
- 我认为我的代码很好,但它在 cin a 之后停止并且没有进一步?
- 如何在MISRA C++之后实施CRTP
- 在 OpenCV 的 namedWindow 之前或之后初始化 Tesseract
- 检测到堆损坏:在正常块 c++ 动态 2D 数组之后
- C++ 如果在 if 为 true 之后运行,为什么还会这样做
- 在 fork() 之后,我在我的程序中不断得到相同的 pid
- OpenSSL C API:如何在程序exec()之后恢复TLS连接?
- 了解在返回值之前和之后使用 EAX 的函数调用
- 在 C++20 之前和之后初始化 std::atomic