HAVE_* 宏的目的是什么?

What is the purpose of HAVE_* macros?

我在 CMake 项目中重用 autotools 项目的一些 C/C++ 源文件的一部分,我看到许多源文件散落着这样的行:

#ifdef HAVE_UNISTD_H
#include <unistd.h>  // for getpid()
#endif

如果 getpid() 是可选的并且它的调用被等效的 HAVE_UNISTD_H 指令包围,我会理解这个构造的目的。但是,没有 HAVE_UNISTD_H 源文件不会编译,并抱怨 getpid() 未定义。这感觉比编译器让我知道 unistd.h 没有找到要神秘得多。

当然,这只是一个例子。其他流行的宏包括 HAVE_STDINT_HHAVE_INTTYPES_H 等,它们的存在是编译源文件所必需的。

为什么要包括 HAVE_* 守卫?我觉得他们只会带来缺点:

Why are HAVE_* guards included at all? I feel they only bring disadvantages: ...

源可以接近替代实现。在那种情况下,您当然不希望因缺少包含而出错。

1例子:

#ifdef HAVE_UNISTD_H
#include <unistd.h>  // for getpid()
#endif
#ifdef HAVE_WINDoWS_H
#include <windows.h> // for GetProcessId()
#endif

1我知道windows支持getpid()

大多数 HAVE_xxx_h 守卫都是 POSIX 出现并标准化 header 文件之前那个时代的残余。在 90 年代初期,您很容易遇到 did 具有 getpid(),但没有工作的 unistd.h 的系统 - 该函数将简单地在另一个 [=28] 中声明=] 文件,否则它根本不会被声明,但它仍然可以工作(只要它的 return 值为 int-sized),因为声明在 K&R 和 C89 C 中是可选的。

当时使用的众多系统之间甚至存在更奇怪的问题。例如,有些系统发布了 time.h,有些发布了 sys/time.h,有些同时发布了这两种系统 - 除了在最后一个类别中有一个子集,其中尝试实际包含两者会导致编译错误! Autoconf 的明确设计目标之一是尽可能支持大量此类系统,而无需提前全部列出,并且一些 long-irrelevant hack 仍然是 carefully documented.

除了上述问题之外,在将代码移植到 non-POSIX 系统(例如 windows 时,将 header 名称与函数支持分离可能会很有用。在这样的系统上,posix header 可能丢失或损坏,实际函数定义来自 gnulib 等可移植性库。