我为我正在制作的小游戏制作了一个简单的帮助库。在这样的库中,我有一些必须尽可能快地执行的核心功能,因为它们每个游戏帧被调用了数千次。
如果我声明它们是“内联”并将它们的声明(library.h
)从它们的实现(library.c
)中分离并将它们包含在游戏文件(game.c
)中,我猜它们没有内联/优化,因为它们直接在game.c
中声明它们并编译游戏与gcc -O3
相比,我的性能提升了60倍。
为了解决这个问题,我决定让我的库成为一个只有头的库。我在library.h
中拥有所有框架常量,变量和函数。将它包括在game.c
仍然给我最大的性能。
现在,问题在于每当我将library.h
包含在多个文件中时(比如game1.c
和game2.c
),我在编译游戏时会得到一长串的duplicate symbol
错误。该库有#pragma once
但仍然出现问题。
如何实际编写仅限标头的库或确保实际优化外部库中的内联函数?
谢谢
正如已经评论过的,你需要在头文件static
中声明函数和全局变量。
static
关键字表示对象(函数或变量)具有内部链接;它只在当前编译单元中可见,并且不会包含在任何符号表中。
使用包含警卫也是一个好主意,因此如果您有另一个包含标题的头文件,并且C源文件包含头文件和其他头文件,则头文件只包含一次。 (FOOLIB_H
的行包括以下示例中的包含警戒。)
考虑以下简单的固定大小的堆栈示例foolib.h:
#ifndef FOOLIB_H
#define FOOLIB_H
#include <stdlib.h>
#define STACK_MAX 256
static size_t stack_size = 0;
static double stack_item[STACK_MAX];
static inline int stack_push(const double item)
{
if (stack_size < STACK_MAX) {
stack_item[stack_size++] = item;
return 0;
} else
return -1;
}
static inline double stack_pop(const double empty)
{
if (stack_size > 0)
return stack_item[--stack_size];
else
return empty;
}
#endif /* FOOLIB_H */
每个编译单元(你单独编译的每个源文件)包含上面的(#include "foolib.h"
),它们可以通过stack_push()
和stack_pop()
获得他们自己的本地私有堆栈。
标记函数static inline
而不仅仅是static
的原因是前者告诉编译器可以完全省略该函数,如果没有使用它。特别是,如果使用gcc -Wall
编译代码,gcc会在未使用static
函数时发出警告,但如果未使用static inline
函数则不会发出警告。除此之外,没有太大的实际差异。