【问题标题】:Why would one use #include_next in a project?为什么要在项目中使用#include_next?
【发布时间】:2026-02-21 04:50:01
【问题描述】:

引用iOSDocumentation on Wrapper Headers

#include_next 不区分 和 "file" 包含,也不检查您指定的文件是否具有相同的 名称为当前文件。它只是查找名为的文件,开始 搜索路径中的目录位于当前目录之后 文件已找到。

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

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

【问题讨论】:

  • ffmpeg 库中的一个例子:#ifndef FFMPEG_COMPAT_AIX_MATH_H #define FFMPEG_COMPAT_AIX_MATH_H #define class class_in_math_h_causes_problems #include_next <math.h> #undef class #endif /* FFMPEG_COMPAT_AIX_MATH_H */

标签: gcc include c-preprocessor


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

    如果您支持某个东西的多个版本,它会很方便。例如,我正在编写支持 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。在这种情况下,您也可以使用statement expressions

    当新版本是“主要”目标时,这种方法很方便,但在有限的时间段内需要旧版本的向后兼容性。因此,您将逐步弃用旧版本,并尝试参考当前版本保持代码整洁。

    替代方案

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

    【讨论】:

      【解决方案3】:

      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
      

      【讨论】: