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_H
、HAVE_INTTYPES_H
等,它们的存在是编译源文件所必需的。
为什么要包括 HAVE_*
守卫?我觉得他们只会带来缺点:
- 重用此类源文件需要确保存在正确的 header 文件 和 定义了正确的
HAVE_*
宏。
- 万一出现错误,开发人员会收到一条更隐秘的消息,即编译器不会报告根本原因(header 未找到),而是报告辅助错误(type/function 未找到).
- 源文件有点长,读起来也有点乏味,即
#include
s 与 #ifdef
s 混合。
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 等可移植性库。
我在 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_H
、HAVE_INTTYPES_H
等,它们的存在是编译源文件所必需的。
为什么要包括 HAVE_*
守卫?我觉得他们只会带来缺点:
- 重用此类源文件需要确保存在正确的 header 文件 和 定义了正确的
HAVE_*
宏。 - 万一出现错误,开发人员会收到一条更隐秘的消息,即编译器不会报告根本原因(header 未找到),而是报告辅助错误(type/function 未找到).
- 源文件有点长,读起来也有点乏味,即
#include
s 与#ifdef
s 混合。
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 等可移植性库。