为什么要在项目中使用 # include_next?

引用 iOS 关于包装头的文档的话:

#include_next不区分 < file > 和“ file”包含,也不检查指定的文件是否具有相同的内容 名称作为当前文件。它只是查找名为,从 与搜索路径中当前 找到了文件。

使用“ # include _ next”可能会导致很大的混淆 只有在没有其他选择的情况下才会使用 不应该在属于特定程序的标题中使用; 应该只用于按照下列方法进行全局修正 包括。

那么,有两个问题,什么是 # include _ next,以及为什么需要使用它?

44894 次浏览

如果您想用自己制作的标头替换默认的标头,例如,假设您想替换“ stdlib.h”,那么可以使用它。您将在项目中创建一个名为 stdlib.h 的文件,该文件将被包含在内,而不是默认的头文件。

如果您想向 stdlib.h 添加一些内容,而不是完全替换它,那么可以使用 # include _ next。创建一个名为 stdlib.h 的新文件,其中包含:

#include_next "stdlib.h"
int mystdlibfunc();

编译器不会像普通的 # include 那样再次递归地包含 你的 stdlib.h,而是继续在其他目录中包含名为“ stdlib.h”的文件。

如果您支持某个东西的多个版本,那么它就很方便。例如,我正在编写支持 PostgreSQL 9.4和9.6的代码。存在许多内部 API 更改,大多数是现有函数的新参数。

兼容头和包装函数

我可以使用 static inline包装器函数为所有内容编写兼容性头文件,基本上是一个包装器 API,我在代码中的任何地方都使用包装器名称。用以下方式说 something_compat.h:

#include "something.h"


static inline something*
get_something_compat(int thingid, bool missing_ok)
{
assert(!missing_ok);
return get_something(thingid);
}

但是把 _compat或任何后缀分散到各处是很丑陋的。

包装头

相反,我可以在包含路径中插入一个兼容性标头,以便在构建旧版本时使用,例如 compat94/something.h:

 #include_next "something.h"


#define get_something(thingid, missing_ok) \
( \
assert(!missing_ok), \
get_something(thingid) \
)

所以剩下的代码可以使用9.6签名。当以9.4为基础构建时,我们将在头搜索路径中加上 -Icompat94的前缀。

需要注意防止多重评估,但是如果你使用 #include_next,你显然不介意依赖 gcc。在这种情况下,您还可以使用 语句表达式

当新版本是“主要”目标时,这种方法很方便,但是在有限的时间内,需要对旧版本进行向下兼容。因此,您正在逐步放弃旧版本,并试图通过引用当前版本来保持代码的整洁。

替代品

或者做一个明智的人,使用 C + + ,并使用重载函数和模板内联函数: p

Include _ next 用作预处理器指令,告诉编译器将文件名 file.h 的搜索路径排除在这个头文件的解析之外。典型的需求是需要使用两个同名的头文件。只有在绝对必要的时候才使用这些特性。

例如:

源 file.c 内容与路径1中的通常 file.h 一样:
#include <file.h>
int main() {
printf("out value: %d", out_val);
exit 0;
}
路径1中的 file.h 头文件包含路径2中的 file.h: Include _ next 指示路径1的子目录不用作 file.h 的搜索路径,而是使用路径2的子目录作为搜索路径。通过这种方式,您可以拥有两个同名文件,而不用担心调用对其本身的循环引用。
# include_next <file.h>
int out_val = UINT_MAX - INT_MAX;
路径2内容中的 file.h
#define INT_MAX 1<<63 - 1
#define UINT_MAX 1<<64 - 1