17

我正在重写我的一个小型 C 数学库,最终将成为用户的静态库,并希望从我的向量数学接口的内联中受益。

我有以下内容:

[mymath.h]

...
...
extern float clampf( float v, float min, float max );
...
...

[mymath.c]

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

   return v;
}

由于我的库将是静态的,并且我只会向用户提供.h(和.lib),因此clampf编译时该函数是否会内联到他们的程序中?

我是否在做正确的事情,但extern.h和 inline 中声明函数.c

4

2 回答 2

19

你几乎是正确的。你实际上有它倒退; 对于内联函数,您必须将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 );

您必须将定义(全文)放在头文件中,如果编译器选择这样做,这将允许包含头文件的任何文件能够使用内联定义。

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

请注意,这可能不适用于 MSVC 编译器,它通常对 C 的支持很差(对 C99 的支持几乎为零)。对于 GCC,您必须为旧版本启用 C99 支持。现代 C 编译器默认支持这种语法。

选择:

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

// mymath.h
static inline float clampf(float v, float min, float max)
{
    ...
}

但是,这不提供函数的非内联版本,因此编译器可能被迫为每个翻译单元创建此函数的副本。

笔记:

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

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

于 2012-04-24T04:21:07.633 回答
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;
}

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

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

于 2012-04-24T04:07:27.363 回答