什么是更好的:功能或定义

时间:2013-07-12 11:47:51

标签: c function optimization c-preprocessor

我有几个简单的功能,比如

#define JacobiLog(x1,x2) ((x1>x2)?x1:x2)+log(1+exp(-fabs(x1-x2)))

什么是更好的实现(代码,编译,内存......) - 如上所述定义或编写一些简单的函数

double JacobiLog(double x1,double x2)
{
     return ((x1>x2) ? x1 : x2) + log(1+exp(-fabs(x1-x2)));
}

6 个答案:

答案 0 :(得分:2)

编译器可能会自动将您的功能设置为内嵌。你应该使用它而不是定义。

在使用define as

的情况下,它还可以避免意外的混淆
double num = JacobiLog(x++, y++);

我让你想象代码替换的问题......

答案 1 :(得分:0)

define 可能可能会更快,但很可能编译器会内联函数(或者你可以标记为内联)并且它们将是相同的。但功能更好,因为它更易读,更容易调试。

答案 2 :(得分:0)

假设一个好的编译器,该函数更好

使用该函数,编译器是否内联代码(假设函数的定义可供使用它的每个人访问,例如,如果它是在{1}}中声明的函数C ++的标题,或者只是一个普通函数,其所有用户都在同一个翻译单元中)。使用宏,它总是内联的,这不一定更快,因为它可能导致代码膨胀,因此更多的缓存未命中和页面错误。

更不用说宏很难读,更糟糕的是要调试。

答案 3 :(得分:0)

即使'define'更快(因为它阻止了函数调用),编译器也可以优化和内联你的函数,并使其快速。

如果您在c ++环境中,则应始终使用模板和函数。它将使您的程序更具可读性并防止出现类型错误。

在C中,宏可能很有用,因为未指定类型(参见下面的示例):

/* Will work with int, long, double, short, etc. */
#HIGHER(VAL1, VAL2)  ((VAL1) > (VAL2) ? (VAL1) : (VAL2))

答案 4 :(得分:0)

这是微观优化。除非您正在进行嵌入式编程并且每个指令都很重要,否则请使用该功能。更不用说log可能比调用函数的开销慢约100倍。因此,如果您的程序主要包含调用此函数,则只能节省大约1%。 [1] 一旦你的程序开始执行重要的其他事情,这种保存将减少到基本上不明显。

编译器可以随意内联函数,这将使两者完全相同。但是,您无法强制编译器执行此操作。 C ++中有一个inline关键字,但这只是一个提示,编译器可以自由忽略它。

请参阅this两者之间的一些差异(这包括内联函数与非内联函数,但如上所述,内联函数与#define基本相同)。该链接的基本结论是“它取决于”。

另请注意,行为上a #define and a function are not 100% equivalent


[1]:数字很大程度上弥补了。如果您想获得准确的结果,请进行基准测试。

答案 5 :(得分:0)

首先(对于一个完整的答案),我们必须承认使用宏可能会产生您可能不想要的惊喜副作用,并且函数可以确保您知道传入的类型,并且您知道每个参数都是精确计算的一次。

使用宏的这些影响往往是问题的根源。

通常编译器会在适当的时候内联函数,如果它能正常工作,那么它应该具有宏的几乎所有优点,但没有很少的预期副作用。

但是,有时候,您实际上可以获得内联编译器可能无法识别的一些好处。例如,如果参数为doubleint,您的宏将暂时将参数转换为long,并在整数运算中执行更多操作(可能具有性能或精度优势)。您可能还会得到整数溢出和不正确的结果。

由于您在“更好”因素列表中包含了“内存”,因此很容易说该函数较小(假设您将编译器配置为针对大小进行优化),但这不一定正确。

显然,作为一个函数,你只需要在内存中复制一个它,所有调用者都可以使用相同的代码,而在每次使用时内联或扩展都会复制代码。您的编译器不太可能隔离宏并将其转换为从代码中的许多不同位置调用的函数。

如果一个永不内联的函数不能小,那就是它在简化方面的地方。我可以想到三种常见的情况:

  1. 如果函数的所有用法都涉及常量参数,则内联简化可能比整个原始函数小。
  2. 使用正确寄存器中的参数执行函数调用所需的寄存器编组代码可能比函数本身长。
  3. 添加函数调用会增加调用者的寄存器压力,迫使它生成更复杂的代码,可能会强制它创建堆栈帧并在进入和退出时保存更多寄存器。