【发布时间】:2026-02-12 19:35:02
【问题描述】:
全部,
我正在编写一些对性能敏感的代码,包括一个 3d 矢量类,它会产生大量的交叉积。作为一名资深的 C++ 程序员,我对宏的弊端和内联函数的各种好处了如指掌。长期以来,我一直认为内联函数的速度应该与宏大致相同。但是,在宏与内联函数的性能测试中,我发现了一个有趣的发现,我希望这是我在某个地方犯了一个愚蠢的错误的结果:我的函数的宏版本似乎比内联版本快 8 倍以上!
首先,一个简单矢量类的可笑精简版:
类 Vector3d { 民众: 双 m_tX,m_tY,m_tZ; Vector3d() : m_tX(0), m_tY(0), m_tZ(0) {} Vector3d(const double &tX, const double &tY, const double &tZ): m_tX(tX), m_tY(tY), m_tZ(tZ) {} 静态内联 void CrossAndAssign ( const Vector3d& cV1, const Vector3d& cV2, Vector3d& cV ) { cV.m_tX = cV1.m_tY * cV2.m_tZ - cV1.m_tZ * cV2.m_tY; cV.m_tY = cV1.m_tZ * cV2.m_tX - cV1.m_tX * cV2.m_tZ; cV.m_tZ = cV1.m_tX * cV2.m_tY - cV1.m_tY * cV2.m_tX; } #define FastVectorCrossAndAssign(cV1,cV2,cVOut) { \ cVOut.m_tX = cV1.m_tY * cV2.m_tZ - cV1.m_tZ * cV2.m_tY; \ cVOut.m_tY = cV1.m_tZ * cV2.m_tX - cV1.m_tX * cV2.m_tZ; \ cVOut.m_tZ = cV1.m_tX * cV2.m_tY - cV1.m_tY * cV2.m_tX; } };这是我的示例基准测试代码:
Vector3d right;
Vector3d forward(1.0, 2.2, 3.6);
Vector3d up(3.2, 1.4, 23.6);
clock_t start = clock();
for (long l=0; l < 100000000; l++)
{
Vector3d::CrossAndAssign(forward, up, right); // static inline version
}
clock_t end = clock();
std::cout << end - start << endl;
clock_t start2 = clock();
for (long l=0; l<100000000; l++)
{
FastVectorCrossAndAssign(forward, up, right); // macro version
}
clock_t end2 = clock();
std::cout << end2 - start2 << endl;
最终结果:在完全关闭优化的情况下,内联版本需要 3200 个滴答声,而宏版本需要 500 个滴答声……打开优化(/O2、最大化速度和其他速度调整)后,我可以得到内联版本降低到 1100 滴答声,这更好,但仍然不一样。
所以我呼吁你们所有人:这是真的吗?我在某个地方犯了一个愚蠢的错误吗?或者内联函数真的这么慢吗?如果是,为什么?
【问题讨论】:
-
是的,更改代码而不检查它是否产生相同的结果是愚蠢错误之母。
-
问题:您确实在启用优化的情况下执行了测试,对吗?编译器通常不会在调试中内联所有内容,因为内联函数不会出现在堆栈帧中,这使得调试变得更加困难。
-
“完全关闭优化后,内联版本需要 [更长]”。那么,当您关闭内联时,您会期待什么?
标签: c++ function macros inline