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

时间:2012-04-21 17:34:54

标签: gcc include c-preprocessor

引用iOS Documentation on Wrapper Headers

  

#include_next无法区分< file>和“文件”包含,也不检查您指定的文件是否相同   将name命名为当前文件。它只是查找名为,起始的文件   在目前的搜索路径中的目录   找到了文件。

     

使用`#include_next'会导致很大的混乱。我们推荐   只有在没有其他选择时才使用它。特别是它   不应该在属于特定程序的标题中使用;它   应该只用于进行全局修正   会运行fixincludes。

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

3 个答案:

答案 0 :(得分:63)

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

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

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

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

答案 1 :(得分:7)

如果您支持某些内容的多个版本,这将非常方便。例如,我正在编写支持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或其他任何后缀都很难看。

包装器标题

相反,我可以在针对旧版本构建时在include路径中插入兼容性标头,例如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。在这种情况下,您还可以使用statement expressions

当新版本是" primary"时,这种方法很方便。目标,但在一段有限的时间内,需要向后兼容旧版本。因此,您要逐步弃用旧版本,并尝试通过引用当前版本来保持代码清洁。

替代

或者是一个懂事的人,使用C ++,并使用重载函数和模板内联函数:p

答案 2 :(得分:0)

include_next用作预处理器指令,以告诉编译器从解析到该头文件的过程中排除直到文件名file.h的搜索路径。典型的需求是当需要使用两个同名的头文件时。仅在绝对必要时才少量使用此类功能。

例如:

源file.c内容与路径1中的常规file.h
#include <file.h>
 int main() {
     printf("out value: %d", out_val);
     exit 0;
     }
包含路径2中的file.h的路径1内容中的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