首页 文章

内联函数与预处理器宏

提问于
浏览
104

内联函数与预处理器宏有何不同?

13 回答

  • 3

    首先,预处理器宏在编译之前的代码中只是"copy paste" . 所以没有 type checking ,有些 side effects 可以出现

    例如,如果要比较2个值:

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

    如果您使用 max(a++,b++) (例如 ab 将递增两次),则会出现副作用 . 相反,使用(例如)

    inline int max( int a, int b) { return ((a<b)?b:a); }
    
  • 8

    预处理器宏只是应用于代码的替换模式 . 它们几乎可以在代码中的任何位置使用,因为在任何编译开始之前它们都会被扩展替换 .

    内联函数是实体函数,其主体直接注入其调用站点 . 它们只能在适合函数调用的地方使用 .

    现在,就类似函数的上下文中使用宏与内联函数而言,请注意:

    • 宏不是类型安全的,并且可以扩展,无论它们是否在语法上是正确的 - 编译阶段将报告由宏扩展问题导致的错误 .

    • 宏可以在您不期望的上下文中使用,从而导致出现问题

    • 宏更灵活,因为它们可以扩展其他宏 - 而内联函数不一定会这样做 .

    • 宏因为扩展而导致副作用,因为输入表达式会复制到模式中出现的任何位置 .

    • 内联函数并不总是保证内联 - 一些编译器只在发布版本中执行此操作,或者在专门配置它们时执行此操作 . 此外,在某些情况下,内联可能是不可能的 .

    • 内联函数可以为变量(特别是静态函数)提供范围,预处理器宏只能在代码块中执行此操作,而静态变量的行为方式不会完全相同 .

  • 67

    内联函数由编译器扩展,其中宏由预处理器扩展,这仅仅是文本替换.Hence

    • 在函数调用期间完成类型检查时,在宏调用期间没有类型检查 .

    • 由于重新评估参数和操作顺序,在宏扩展期间可能会出现不期望的结果和低效率 . 例如

    #define MAX(a,b) ((a)>(b) ? (a) : (b))
    int i = 5, j = MAX(i++, 0);
    

    会导致

    int i = 5, j = ((i++)>(0) ? (i++) : (0));
    
    • 在宏扩展之前不评估宏参数
    #define MUL(a, b) a*b
    int main()
    {
      // The macro is expended as 2 + 3 * 3 + 5, not as 5*8
      printf("%d", MUL(2+3, 3+5));
     return 0;
    }
    // Output: 16`
    
    • 无法在宏中使用return关键字来返回值,就像函数一样 .

    • 内联函数可以重载

    • 传递给宏的标记可以使用名为Token-Pasting运算符的运算符##连接 .

    • 宏通常用于代码重用,其中内联函数用于消除函数调用期间的时间开销(超时)(避免跳转到子例程) .

  • 0

    关键的区别是类型检查 . 编译器将检查您作为输入值传递的是否是可以传递给函数的类型 . 对于预处理器宏来说情况并非如此 - 它们在任何类型检查之前都会被扩展,这会导致严重且难以检测到的错误 .

    Here是其他几个不太明显的要点 .

  • 0

    要为已经给出的内容添加另一个区别:您无法在调试器中单步执行 #define ,但可以单步执行内联函数 .

  • 10

    宏忽略了名称空间 . 这使他们变得邪恶 .

  • 13

    内联函数类似于宏(因为函数代码在编译时在调用时展开),内联函数由编译器解析,而宏则由预处理器扩展 . 因此,有几个重要的区别:

    • 内联函数遵循在正常函数上强制执行的所有类型安全协议 .

    • 内联函数使用与任何其他函数相同的语法指定,除了它们在函数声明中包含inline关键字 .

    • 作为内联函数的参数传递的表达式被计算一次 .

    • 在某些情况下,作为参数传递给宏的表达式可以多次计算 . http://msdn.microsoft.com/en-us/library/bf6bf4cf.aspx

    • 宏在预编译时展开,不能用它们进行调试,但可以使用内联函数 .

    -- good article: http://www.codeguru.com/forum/showpost.php?p=1093923&postcount=1

    ;

  • 0

    内联函数将保持值语义,而预处理器宏只是复制语法 . 如果使用参数,则可以使用预处理器宏获得非常微妙的错误多次 - 例如,如果参数包含像“i”那样执行两次的突变,那就非常令人惊讶了 . 内联函数不会出现此问题 .

  • 1

    内联函数在语法上的行为就像普通函数一样,为函数局部变量提供类型安全性和范围,如果是方法则提供对类成员的访问 . 此外,在调用内联方法时,您必须遵守私有/受保护的限制 .

  • 12

    在GCC中(我不确定其他人),声明一个内联函数,只是对编译器的一个暗示 . 在一天结束时,仍然需要编译器决定它是否包含函数体,无论何时调用它 .

    内联函数和预处理器宏之间的差异相对较大 . 预处理器宏在一天结束时只是文本替换 . 您放弃了编译器执行检查参数和返回类型的类型检查的能力 . 对参数的评估是非常不同的(如果你传递给函数的表达式有副作用,你将有一个非常有趣的时间调试) . 关于函数和宏的使用位置存在细微差别 . 例如,如果我有:

    #define MACRO_FUNC(X) ...
    

    其中MACRO_FUNC显然定义了函数体 . 需要特别小心,以便在所有情况下都可以正常运行,可以使用一个函数,例如写得不好的MACRO_FUNC会导致错误 .

    if(MACRO_FUNC(y)) {
     ...body
    }
    

    可以使用正常功能而没有问题 .

  • 2

    从编码的角度来看,内联函数就像一个函数 . 因此,内联函数和宏之间的差异与函数和宏之间的差异相同 .

    从编译的角度来看,内联函数类似于宏 . 它被直接注入到代码中,而不是被调用 .

    通常,您应该将内联函数视为常规函数,并将一些次要优化混合在一起 . 与大多数优化一样,由编译器决定它是否真正关心应用它 . 由于各种原因,编译器通常会高兴地忽略程序员内联函数的任何尝试 .

  • 118

    如果在其中存在任何迭代或递归语句,则内联函数将表现为函数调用,以防止重复执行指令 . 它有助于节省程序的整体内存 .

  • -1
    #include<iostream>
    using namespace std;
    #define NUMBER 10 //macros are preprocessed while functions are not.
    int number()
    { 
        return 10;
    }
    /*In macros, no type checking(incompatible operand, etc.) is done and thus use of micros can lead to errors/side-effects in some cases. 
    However, this is not the case with functions.
    Also, macros do not check for compilation error (if any). Consider:- */
    #define CUBE(b) b*b*b
    int cube(int a)
    {
     return a*a*a;
    }
    int main()
    {
     cout<<NUMBER<<endl<<number()<<endl;
     cout<<CUBE(1+3); //Unexpected output 10
     cout<<endl<<cube(1+3);// As expected 64
     return 0;
    }
    

    宏通常比函数更快,因为它们不涉及实际的函数调用开销 .

    宏的一些缺点:没有类型检查 . 难以调试,因为它们导致简单的替换 . 宏没有命名空间,因此一段代码中的宏可以影响其他部分 . 宏可能会导致副作用,如上面的CUBE()示例所示 .

    宏通常是一个班轮 . 但是,它们可以包含多行 . 功能中没有这样的约束 .

相关问题