C语言中的存储类说明符有哪些?各自的含义如何?
inline int foo(int a, int b) { return a + b; } int main(int argc, char *argv[]){return(1,2);
*ANSI C, ISO/IEC C89/C90:标准中没有inline关键字.
*GNU C89/C90:
1、static inline:函数名标识符的作用域为当前编译单元(translation unit),允许其他编译单元中有重名定义. 这里的inline建议编译器,函数在被调用时可以直接展开函数体,但是否展开取决于编译器.(譬如,如果优化级别为-O0,则必须按函数地址调用,此时编译器会忽略inline请求,将函数编译为普通函数;或者,出现了递归调用,编译器也无法内联这个函数)
2、inline:在当前编译单元内,和static inline语义相同,都是建议编译器在当前编译单元内展开函数体(是否展开取决于编译器). 但同时编译器会对该函数生成一份普通函数的代码,在其他编译单元内可以调用,与普通的extern函数调用无异.
3、extern inline:相当诡异. 这样的函数定义只为内联而提供. 如果强行用普通函数调用方式调用该函数(譬如,优化级别为-O0,或者按函数指针调用),则链接器会认为存在另一个同名的普通函数. 如果没有这个同名普通函数的定义,则链接器会报告找不到符号.
*ISO/IEC C99/C11:
1、static inline:和GNU C89/C90中的语义完全相同.
2、inline:很类似GNU C89/C90中的extern inline. 标准文档中的解释相当晦涩:允许(但不要求)编译器在当前编译单元内展开函数体(原文的描述是“相比正常的函数调用机制,让内联函数调用尽可能快”,而文档下面的脚注中提到,可能的选择是“内联替换”,见ISO/IEC 9899:1999或ISO/IEC 9899:2011),是否内联由编译器设计者自行决定,同时也允许外部存在同名的普通函数定义. 经测试最新版本的Clang和GCC在标准-std=c99和-std=c11下会在可以内联的情况下(例如优化级别为-O2)采用内联版本.
3、但标准文档中同时也规定了,若在函数声明中加入extern,则相应的内联函数定义成为所谓的外部定义,行为和GNU C89/C90的inline相同:在当前编译单元中建议编译器展开函数体,同时生成一份普通函数的代码,在其他编译单元中也可调用.
4、extern inline:标准文档中未见extern inline的定义.
*GNU C99/C11:采用与ISO/IEC C99/C11相同的语义.
最新版本的Clang和GCC默认均采用GNU C11标准,因此会出现不优化代码时找不到内联函数符号的错误.