C中宏和函数在指令内存和速度方面的差异

C中宏和函数在指令内存和速度方面的差异,c,macros,c-preprocessor,C,Macros,C Preprocessor,据我所知,宏和函数之间的区别在于,宏调用将被定义中的指令所取代,函数完成整个推送、分支和弹出操作。这是对的,还是我理解错了 此外,如果这是正确的,这意味着宏将占用更多的空间,但速度会更快(因为缺少push、branch和pop指令),不是吗?如果C编译器没有优化,您所写的关于性能影响的内容是正确的。但是优化编译器可以像宏一样内联函数,因此内联函数调用的运行速度与宏相同,并且没有推送/弹出开销。要触发内联,请在编译器设置中启用优化(例如,gcc-O2),并将函数作为静态内联放入.h文件中 请注意,

据我所知,宏和函数之间的区别在于,宏调用将被定义中的指令所取代,函数完成整个推送、分支和弹出操作。这是对的,还是我理解错了


此外,如果这是正确的,这意味着宏将占用更多的空间,但速度会更快(因为缺少push、branch和pop指令),不是吗?

如果C编译器没有优化,您所写的关于性能影响的内容是正确的。但是优化编译器可以像宏一样内联函数,因此内联函数调用的运行速度与宏相同,并且没有推送/弹出开销。要触发内联,请在编译器设置中启用优化(例如,
gcc-O2
),并将函数作为
静态内联
放入
.h
文件中

请注意,有时内联/宏更快,有时实际函数调用更快,这取决于代码和编译器。如果函数体很短(大部分都会被优化掉),通常内联比函数调用更快


另一个重要区别是,宏可以接受不同类型的参数,并且宏定义可以适用于多种类型(但编译器不会为您执行类型检查,因此,如果使用参数类型错误的宏,则可能会出现不希望出现的行为或隐晦的错误消息)。这个多态性很难用C中的函数来模拟(但C++中的函数重载和函数模板很容易)。但您还应该注意,宏中没有类型检查,这可能会导致副作用。在插入宏时也应该非常小心

这在20世纪80年代可能是正确的,但现代编译器要好得多

函数并不总是推送和弹出堆栈,尤其是当它们是叶函数或具有尾部调用时。此外,函数通常是内联的,即使它们是在其他转换单元中定义的,也可以内联(这称为链接时间优化)

但你是对的,一般来说,当优化被关闭时,宏将被内联,而函数将不会被内联。任何一个版本都可能占用更多空间,这取决于宏/函数的细节


函数以两种方式使用空间:主体使用空间,函数调用使用空间。如果函数体非常小,实际上可以节省空间来内联它。

您的理解是正确的一半。关键是宏是在编译之前解析的。你应该把它们看作是复杂的文本替换工具(这太简单了,但归根结底就是这样)

因此,区别在于在构建过程中何时使用代码

这与编译器在创建最终二进制代码时真正使用它的问题是正交的。它或多或少可以自由地做它认为正确的事情,以产生预期的行为。在C++中,您只能用“代码>内联< /COD>关键字”来提示您的偏好。编译器可以随意忽略该提示

同样,这与整个预处理器业务是正交的。毕竟,没有什么阻止您编写使用C++代码>内联< /COD>关键字的宏代码。同样,没有人阻止你编写宏,这会导致大量递归的C++函数,编译器即使想做,也可能不能内联。 结论是你的问题是错误的。这是一个一般性的问题,即二进制文件具有大量内联函数,而二进制文件具有大量实际函数调用。宏只是一种技术,你可以用这种或那种方式来影响权衡,没有宏你也会问自己同样的问题

内联函数总是以空间换取速度的假设是错误的。内联错误(即太大)的函数甚至会对速度产生负面影响。像这种观点一样,不要猜测,而是测量


您应该阅读以下常见问题解答:

宏只是文本复制。预处理器只是用您提供的别名文本替换宏。与此相关,内联会更快?@DAHANS:比什么快?因此内联函数调用的运行速度与宏相同,还有推送/弹出开销,我想你想说,没有推送/弹出…我更新了关于内联的速度含义的答案。当然,宏和内联函数之间最重要的区别之一是,很容易在无意中对参数进行两次计算,或者,如果参数是复杂表达式,则会弄乱优先级。没有理由选择宏而不是内联函数。(当然,偶尔使用宏还有其他原因。
\uuuuu LINE\uuuuu
\uuuu FILE\uuuu
仅在宏中工作。)