如何正确内联静态库

McB*_*Bob 15 c

我正在重写我的一个小C数学库,它最终会成为用户的静态库,并希望从我的矢量数学界面的内联中受益.

我有以下内容:

[mymath.h]

...
...
extern float clampf( float v, float min, float max );
...
...
Run Code Online (Sandbox Code Playgroud)

[mymath.c]

inline float clampf( float v, float min, float max )
{
    if( v < min ) v = min;
    if( v > max ) v = max;

   return v;
}
Run Code Online (Sandbox Code Playgroud)

由于我的库是静态的,我只是要向用户提供.h(和.lib),clampf在编译时是否会在程序中内联函数?

我做了正确的事情,但在声明函数extern.h中和内联.c

Die*_*Epp 17

你几乎是正确的.你实际上倒退了; 对于内联函数,您必须将inline定义放在头文件中,并将extern声明放在C文件中.

// mymath.h
inline float clampf( float v, float min, float max )
{
    if( v < min ) v = min;
    if( v > max ) v = max;

    return v;
}

// mymath.c
#include "mymath.h"
extern float clampf( float v, float min, float max );
Run Code Online (Sandbox Code Playgroud)

您必须将定义(完整正文)放在头文件中,这将允许任何包含头文件的文件能够在编译器选择时使用内联定义.

您必须将extern声明(原型)放在源文件中,以告诉编译器在库中发出该函数的外部版本.这为您的库提供了非内联版本的一个位置,因此编译器可以在内联函数或使用通用版本之间进行选择.

请注意,这可能不适用于MSVC编译器,MSVC编译器通常对C的支持非常差(并且几乎没有支持C99).对于GCC,您必须为旧版本启用C99支持.Modern C编译器默认支持此语法.

替代方案:

您可以更改标题以获得static inline版本,

// mymath.h
static inline float clampf(float v, float min, float max)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

但是,这不提供函数的非内联版本,因此可能会强制编译器为每个转换单元创建此函数的副本.

笔记:

  1. C99内联规则并不完全直观.文章" C中的内联函数 "(镜像)详细描述了它们.特别是,请跳到底部并查看"使用内联函数的策略".我更喜欢方法#3,因为GCC已经默认为C99方法一段时间了.

  2. 从技术上讲,您永远不需要设置extern函数声明(或定义),因为extern它是默认值.我把它放在那里强调.

  • @kay:阅读整个答案.你必须在某个地方的翻译单元中为函数添加一个`extern`声明(即不在标题中).这将导致在该模块中发出非内联版本.(并且通常应该从该单元中包含头文件.)请参阅C99标准,或阅读http://www.greenend.org.uk/rjk/tech/inline.html (3认同)

kay*_*kay 6

您应该static inline在.h文件中定义您的函数:

static inline float clampf( float v, float min, float max )
{
    if( v < min ) v = min;
    if( v > max ) v = max;

    return v;
}
Run Code Online (Sandbox Code Playgroud)

.c文件中必须不存在该函数.

编译器可能决定不内联函数,但使其成为正确的函数调用.因此,每个生成的.o文件都可能包含该函数的副本.

  • 如果函数是内联的,那么每次调用函数都会导致代码被复制.这是设计? (3认同)
  • 如果我没记错的话,链接器将不会合并"静态内联"函数的不同副本.因此,与`inline` /`extern`版本相比,您最终会得到重复的代码.(我怀疑,出血边缘连接器可以消除重复,但它们仍然与普通使用相去甚远.) (2认同)