我为一个小小的游戏制作了一个简单的帮助库。在这样的库中,我有一些必须尽可能快地执行的核心功能,因为它们在每个游戏帧中被调用了数千次。
如果我宣布他们"内联"并将他们的声明(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
,但问题仍然存在。
如何实际编写仅限标头的库或确保实际优化外部库中的内联函数?
由于
答案 0 :(得分:2)
正如已经评论的那样,你需要在头文件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
函数则不会发出警告。除此之外,没有太大的实际差异。