66

引用有关 Wrapper Headers 的 iOS文档

#include_next不区分 <file> 和 "file" 包含,也不检查您指定的文件是否与当前文件同名。它只是查找命名的文件,从搜索路径中找到当前文件的目录之后的目录开始。

使用 `#include_next' 会导致很大的混乱。我们建议仅在没有其他选择时才使用它。特别是,它不应该用在属于特定程序的头文件中;它应该仅用于按照 fixincludes 进行全局更正。

那么,两个问题,什么是#include_next,以及为什么你需要使用它?

4

3 回答 3

94

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

如果您想向 stdlib.h 添加一些东西而不是完全替换它,则使用 #include_next。您创建一个名为 stdlib.h 的新文件,其中包含:

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

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

于 2012-04-21T19:30:34.060 回答
12

如果您支持某些东西的多个版本,这很方便。例如,我正在编写支持 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

于 2016-08-30T15:20:51.560 回答
2

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 子目录作为搜索路径。这样,您可以拥有 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
于 2020-03-12T02:47:47.680 回答