我对我的代码的性能有疑问。 假设我在C中有一个结构点:
typedef struct _CPoint
{
float x, y;
} CPoint;
和我使用struct的函数。
float distance(CPoint p1, CPoint p2)
{
return sqrt(pow((p2.x-p1.x),2)+pow((p2.y-p1.y),2));
}
我想知道为#define替换这个函数是否明智,
#define distance(p1, p2)(sqrt(pow((p2.x-p1.x),2)+pow((p2.y-p1.y),2)));
我认为它会更快,因为没有函数开销,我想知道我是否应该将这种方法用于我的程序中的所有其他函数来提高性能。所以我的问题是:
我应该用#define替换所有函数以提高代码的性能吗?
答案 0 :(得分:8)
没有。您永远不应该根据感知的性能差异在宏和函数之间做出决定。你应该根据宏上函数的优点来评估它。一般来说选择功能。
宏有很多隐藏的缺点可以咬你。例如,您在此处对宏的转换是不正确的(或者至少不是保留原始函数的语义)。宏distance
的参数每次被评估2次。想象一下,我做了以下电话
distance(GetPointA(), GetPointB());
在宏版本中,这实际上导致4个函数调用,因为每个参数都被计算两次。如果将distance
作为函数保留,则只会产生3个函数调用(距离和每个参数)。注意:我忽略了sqrt
和pow
在上述计算中的影响,因为它们在两个版本中都是相同的。
答案 1 :(得分:3)
有三件事:
distance
虽然功能保证某种类型的安全性,但由于需要在每个函数调用时使用堆栈帧,它们也会导致性能损失。来自内联函数的代码会在调用站点复制,因此不会支付罚金 - 但是,您的代码大小会增加。宏不提供类型安全性,也涉及文本替换。
从三者中选择,我通常使用内联函数。宏只有在它们非常短并且在这种形式下非常有用时(例如来自Linux内核的hlist_for_each
)
答案 2 :(得分:3)
我建议使用inline
函数而不是宏。它会给你一个宏的任何可能的性能优势,没有丑陋。 (宏有一些问题使得它们非常容易作为函数的一般替代。特别是,每次使用时都会对宏args进行评估,而在“调用”之前对函数args进行一次评估。)
inline float distance(CPoint p1, CPoint p2)
{
float dx = p2.x - p1.x;
float dy = p2.y - p1.y;
return sqrt(dx*dx + dy*dy);
}
(注意我也将pow(dx, 2)
替换为dx * dx
。这两个是等效的,乘法更有效。有些编译器可能会尝试优化调用pow
。 ..但猜猜他们用什么代替它。)
答案 3 :(得分:3)
Jared是对的,在这种特定情况下,pow
次呼叫和sqrt
呼叫所花费的周期将比呼叫中花费的周期多2个数量级。 distance
。
有时人们认为小代码等于小时间。不是这样。
答案 4 :(得分:1)
如果使用相当成熟的编译器,那么如果优化被打开,propaby将在汇编级别为您执行此操作。
对于gcc -O3或(对于“小”函数),即使-O2选项也会这样做。
有关详细信息,您可以考虑在此处http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html阅读“-finline *”选项。