我为我正在制作的一个小游戏制作了一个简单的辅助库。在这样的库中,我有一些核心函数必须尽可能快地执行,因为它们每个游戏帧被调用数千次。
如果我将它们声明为"内联"并将它们的声明(library.h
)与它们的实现(library.c
)分开并将它们包含在游戏文件(game.c
)中,我想它们没有内联/优化,因为直接在game.c
中声明它们并使用gcc -O3
编译游戏,使性能提升了60倍以上。
为了解决这个问题,我决定将我的库设置为仅标题库。我所有的框架常量、变量和函数都在library.h
.将其包含在game.c
中仍然可以为我提供最大的性能。
现在,问题是每当我在多个文件(例如game1.c
和game2.c
)中包含library.h
时,我在编译游戏时都会收到一长串duplicate symbol
错误。库已#pragma once
,但问题仍然存在。
如何实际编写仅标头库或确保来自外部库的内联函数实际上得到了优化?
谢谢
正如alk已经评论的那样,您需要在头文件中声明函数和全局变量static
。
static
关键字表示对象(函数或变量)具有内部链接;它仅在当前编译单元中可见,并且不会包含在任何符号表中。
使用 include 保护也是一个好主意,这样,如果您有另一个包含头文件的头文件,并且 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
函数时不会发出警告。除此之外,没有太大的实际区别。