IMO都只使该功能具有翻译单元的范围。
“静态”和“静态内联”功能有什么区别?
为什么inline
应放在头文件中,而不是放在.c
文件中?
答案 0 :(得分:90)
inline
指示编译器尝试将函数内容嵌入到调用代码中,而不是执行实际调用。
对于频繁调用的小功能,可以产生很大的性能差异。
然而,这只是一个“提示”,并且编译器可能会忽略它,并且大多数编译器将尝试“内联”,即使在未使用关键字时,作为优化的一部分,也是可能的。
例如:
static int Inc(int i) {return i+1};
.... // some code
int i;
.... // some more code
for (i=0; i<999999; i = Inc(i)) {/*do something here*/};
这个紧密循环将在每次迭代时执行函数调用,并且函数内容实际上远小于编译器执行调用所需的代码。 inline
基本上会指示编译器将上面的代码转换为等效的:
int i;
....
for (i=0; i<999999; i = i+1) { /* do something here */};
跳过实际的函数调用并返回
显然,这是一个展示要点的例子,而不是真正的代码。
static
指的是范围。在C中,它表示函数/变量只能在同一个翻译单元中使用。
答案 1 :(得分:67)
默认情况下,内联定义仅在当前翻译单元中有效。
如果存储类为extern
,则标识符具有外部链接,内联定义也提供外部定义。
如果存储类为static
,则标识符具有内部链接,并且内联定义在其他翻译单元中不可见。
如果未指定存储类,则内联定义仅在当前转换单元中可见,但标识符仍具有外部链接,并且必须在不同的转换单元中提供外部定义。如果在当前转换单元中调用函数,编译器可以自由使用内联或外部定义。
由于编译器可以自由内联(并且不内联)任何其定义在当前翻译单元中可见的函数(并且,由于链接时优化,即使在不同的翻译单元中,尽管C标准不真正考虑到这一点),对于大多数实际用途,static
和static inline
函数定义之间没有区别。
inline
说明符(如register
存储类)只是编译器提示,编译器可以完全忽略它。符合标准的非优化编译器只需要遵守它们的副作用,优化编译器将在有或没有明确提示的情况下进行这些优化。
inline
和register
并没有用,因为它们指示编译器在程序员编写会使优化无法实现的代码时抛出错误:外部inline
定义可以' t具有内部链接的引用标识符(因为这些标识符在不同的转换单元中不可用)或定义具有静态存储持续时间的可修改局部变量(因为这些变量不会共享翻译单元的状态),并且您不能获取{{的地址1}} - 限定变量。
就我个人而言,我使用约定在标题register
中标记static
函数定义,因为将函数定义放在头文件中的主要原因是使它们无法使用。
通常,除了标题中的inline
声明之外,我只使用static inline
函数和static const
对象定义。
我从未编写过extern
函数,其存储类与inline
不同。
答案 2 :(得分:14)
根据我对GCC的经验,我知道static
和static inline
在编译器发出有关未使用函数的警告方面有所不同。更确切地说,当您声明static
函数并且它未在当前转换单元中使用时,编译器会生成有关未使用函数的警告,但您可以通过将其更改为static inline
来禁止该警告。
因此,我倾向于认为static
应该在翻译单元中使用,并且受益于额外检查编译器查找未使用的函数。并且应在头文件中使用static inline
来提供可以内联的函数(由于没有外部链接)而不发出警告。
不幸的是,我找不到任何有关该逻辑的证据。即使从GCC文档中,我也无法断定inline
禁止未使用的功能警告。如果有人会分享这方面的描述,我将不胜感激。
答案 3 :(得分:5)
一个区别在于语言级别但是流行的实现级别:默认情况下,某些版本的gcc会从输出中删除未引用的static inline
函数,但即使未引用也会保留简单的static
函数。我不确定这适用于哪个版本,但从实际角度来看,这意味着始终在标题中使用inline
static
函数可能是一个好主意。
答案 4 :(得分:3)
在C中,static
表示您定义的函数或变量只能在此文件中使用(即编译单元)
因此,static inline
表示只能在此文件中使用的内联函数。
修改强>
编译单元应该是翻译单元