代码之家  ›  专栏  ›  技术社区  ›  eliego

inline和define在实践中有什么不同?

  •  9
  • eliego  · 技术社区  · 16 年前

    正如标题所说,inline关键字和define preprocessor指令在实践中有什么区别?

    6 回复  |  直到 10 年前
        1
  •  44
  •   Pavel Radzivilovsky    13 年前

    #define 是一个预处理器工具,具有宏语义。考虑一下,如果 max(a,b) 宏定义为

    #define max(a,b) ((a)>(b)?(a):(b)) :

    val = max(100, GetBloodSample(BS_LDL)) 会溢出更多无辜的血液,因为函数实际上会被调用两次。这可能意味着实际应用程序的性能有很大的差异。

    例2:

    val = max(3, schroedingerCat.GetNumPaws()) 程序逻辑上的严重差异 ,因为这可能会意外地返回小于3的数字—这是用户无法预料的。

    val = max(x, y++) 可能增加 y 不止一次。


    对于内联函数,这些都不会发生。

        2
  •  2
  •   caf    16 年前

    #define )总是按书面形式替换,并且可能有双重评估问题。

    inline 另一方面,它纯粹是建议性的—编译器可以随意忽略它。根据C99标准 内联 函数也可以有外部链接,创建一个可以链接的函数定义。

        3
  •  2
  •   Jens Gustedt    16 年前

    inline 宏实现不同的目的。他们之间的分歧不应被视为意识形态上的分歧,更重要的是,他们可以很好地合作。

    #define P99_ISSIGNED(T) ((T)-1 < (T)0)
    

    它给出了一个编译时表达式,表示整型是否有符号。也就是说,当表达式的类型未知(在定义中)并且您想对其做些什么时,理想情况下使用它们。另一方面,宏的缺点是它们的参数可能会被计算多次,这是不好的,因为会产生副作用。

    功能( )另一方面是打字,这使他们更严格,或措辞消极,不太灵活。考虑功能

    inline uintmax_t absU(uintmax_t a) { return a; }
    inline uintmax_t absS(uintmax_t a) {
       return (-a < a) ? -a : a;
    }
    

    第一个实现了琐碎的 abs 无符号整数类型的函数。第二种是针对有符号类型实现的。(是的,它接受一个unsigned作为参数,这是出于目的。)

    我们可以把它们用于任何积分类型。但是,返回类型的宽度总是最大的,要知道如何在两者之间进行选择有一定的困难。

    #define ABS(T, A) ((T)(P99_ISSIGNED(T) ? absS : absU)(A))
    

    • 函数族
    • 适用于任何积分类型
    • 任何最近的和体面的 编译器将创建最佳代码

    )嗯,我承认 有点做作,但我希望你能理解。)

        4
  •  1
  •   DarkDust    16 年前

    #define 比内联函数更难编写和编辑。您可以像任何普通函数一样定义内联函数,并且可以毫无问题地定义变量。假设您想在另一个函数中多次调用一个代码块,而该代码块需要它自己的变量:使用内联函数更容易(是的,您可以使用#defines和 do { ... } while (0); 但这是你必须考虑的事情)。

    另外,启用调试后,通常会得到一个内联函数的“模拟”堆栈框架,这有时可能会使调试变得更容易(至少在编译/链接gcc时是这样) -g

    除此之外,结果应该是几乎相同的。

        5
  •  0
  •   Chris    16 年前

    类似于宏的函数在定义它们的地方为您提供绝对零的健全性检查。当你把一个宏搞砸的时候,它在一个地方可以正常工作,在另一个地方会坏掉,直到你失去了几个小时的工作/睡眠时间,你才知道为什么。类似宏的函数不会对数据进行操作,而是对源代码进行操作。有时这是好的,例如当您需要使用 文件 和 内置函数,但大多数情况下,它也可以通过内联函数来完成,内联函数在定义时会像其他函数一样检查语法。