我正在将一个Autotools项目中的一些C/C++源文件重用于一个CMake项目中,我看到许多源文件上都有类似以下的代码行:
#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_*
开关?我认为它们只会带来不利影响:
- 重用这样的源文件需要确保正确的头文件存在和正确的
HAVE_*
宏已定义。 - 如果出现错误,开发者会收到更加难懂的消息,即编译器不会报告根本原因(找不到头文件),而是一个次要错误(类型/函数未找到)。
- 源文件会变得有些冗长,阅读起来有些繁琐,即
#include
和#ifdef
混杂在一起。
getpid()
的错误消息。这既是支持宏的原因,也是反对宏的原因,具体取决于你问谁。 - user743382#ifdef HAVE_UNISTD_H / #include <unistd.h> / #endif
进行代码编写而没有任何后备方案,这与HAVE_UNISTD_H
检查的意图相违背。 代码应为缺失内容提供一个通用声明 ——例如int getpid(void);
。 否则,检查就是毫无意义的。 这是最初的想法。 在 C90 年代,你可以通过隐式函数声明逃脱 ——但如果 Microsoft 实际上实现了 C99 或 C11 (二者皆有也好),则 C90 应该早已被遗忘。 - Jonathan Leffler