9

根据 C FAQ,在 C 中“内联”代码基本上有 3 种实用方法:

#define MACRO(arg1, arg2) do { \
    /* declarations */ \
    stmt1;   \
    stmt2;   \
    /* ... */  \
    } while(0)    /* (no trailing ; ) */

或者

#define FUNC(arg1, arg2) (expr1, expr2, expr3)

为了澄清这一点,表达式中使用了参数,逗号运算符返回最后一个表达式的值。

或者

使用作为gcc 扩展和 c99 标准inline支持的声明。

do { ... } while (0)方法在Linux内核中被广泛使用,但我没有经常遇到其他两种方法。

我特别指的是多语句“函数”,而不是像 MAX 或 MIN 这样的单语句。

每种方法的优缺点是什么,为什么在各种情况下您会选择其中一种?

4

3 回答 3

16

谈到宏的特定用途,即充当“函数”的宏,我会提到内联函数中不能具有的宏的以下优点:

懒惰的论证评估。例如,像这样的宏

#define SELECT(f, a, b) ((f) ? (a) : (b))

将保留三元运算符的惰性参数评估属性:仅评估所选参数,而不评估其他参数。一个简单的内联函数类比会提前评估这两个参数,从而做额外的不必要的工作。

访问上下文。宏可用于实现“局部函数”的一些相似之处,即可以访问局部变量和封闭函数参数的重复代码片段。

类型独立性(和类型参数)。宏允许您编写与类型无关的“函数”(参见上面的示例)。如果你不能摆脱类型依赖,你可以将类型作为参数传递给宏。

宏的上述属性,我作为它们的优点,可能会被滥用而导致重大故障(因此也可能被表现为缺点)。但这就是 C 语言中许多语言特性的特点。

于 2009-10-15T11:13:06.607 回答
5

使用 inline 关键字的一个优点是您可以通过函数原型检查参数的类型。使用宏你不会得到类似的东西,所以如果你把错误类型的东西放入宏中,它很可能会产生奇怪的错误。(虽然不像 C++ 中的模板错误那么可怕。)

使用宏的一个优点是你可以做一些时髦的事情,比如连接和使用#arg 将宏参数转换为字符串。使用预处理器宏的另一个好处是您可以轻松地检查它们如何使用 cpp 展开以展开它们。这就是您调试这些错误的方式。

宏定义函数的另一个有用点是,如果需要,您可以在其中添加一条return语句来停止父函数。使用内联函数,您必须返回一个值,然后检查返回值。

于 2009-10-15T10:28:18.917 回答
0

在使用任何构造时,我能看到的唯一优点是使其代码更快。

所以,选择一种能提供最快代码的方法!

如果都一样,那我觉得它更清晰

  1. “标准”功能
  2. 一个inline函数
  3. #define ... do {} while(0)方法_
  4. 带有逗号分隔表达式的宏
于 2009-10-15T10:17:25.980 回答