yas*_*sar 3 c static inline header-files
当我检查其他人的代码时,我有时会遇到在头文件中实现的静态内联函数,而不是C文件中的常规函数实现.
例如,cache.h头文件(https://github.com/git/git/blob/master/cache.h)git包含许多这样的功能.其中一个复制在下面;
static inline void copy_cache_entry(struct cache_entry *dst,
const struct cache_entry *src)
{
unsigned int state = dst->ce_flags & CE_HASHED;
/* Don't copy hash chain and name */
memcpy(&dst->ce_stat_data, &src->ce_stat_data,
offsetof(struct cache_entry, name) -
offsetof(struct cache_entry, ce_stat_data));
/* Restore the hash state */
dst->ce_flags = (dst->ce_flags & ~CE_HASHED) | state;
}
Run Code Online (Sandbox Code Playgroud)
我想知道使用静态内联函数与常规函数相比有什么优势.有没有可以用来选择适应哪种风格的指南?
内联是为了优化.但是,一个鲜为人知的事实是,inline它还会损害性能:您的CPU具有固定大小的指令缓存,并且内联具有在多个位置复制函数的缺点,这使得指令缓存效率降低.
因此,从性能的角度来看,通常不建议声明函数,inline 除非它们太短以至于它们的调用比它们的执行更昂贵.
为此,函数调用需要10到30个CPU时间周期(取决于参数的数量).算术运算通常需要一个周期,但是,来自第一级缓存的内存负载需要三到四个周期.因此,如果你的函数比最多三次内存访问和一些算术的简单序列更复杂,那么内联它就没什么意义了.
我通常采用这种方法:
如果函数像递增单个计数器一样简单,并且如果它在整个地方使用,我会内联它.这种情况很少见,但一个有效的例子是引用计数.
如果函数仅在单个文件中使用,我将其声明为static,而不是inline.这具有以下效果:编译器可以看到何时恰好使用这样的函数一次.如果它看到了,它很可能会内联它,无论它多么复杂,因为它可以证明内联没有任何缺点.
所有其他功能都不static是inline.
您的问题中的示例是一个边界示例:它包含一个函数调用,因此它看起来太复杂了,无法一眼内联.
但是,该memcpy()功能很特殊:它更多地被视为语言的一部分而不是库函数.大多数编译器都会内联它,并在大小是一个很小的编译时常量时对它进行大量优化,这就是代码中的情况.
通过该优化,该功能确实简化为简短的序列.我不知道它是否涉及大量内存,因为我不知道复制的结构.如果该结构很小,inline在这种情况下添加关键字似乎是个好主意.