确定 C 预处理器指令中的操作系统变量



我正在发布另一个我无法解决的编程任务。假设我们编写特定于操作系统的预处理器指令,例如:

#if OS == Linux
/* Linux-specific instructions */
...
#else
#if OS == Darwin
/* Mac OSX-specific instructions */
...
#else
/* Program code for other OS */
...
#endif
#endif

我们不允许使用#define OS Linux;而是使用编译器(或者在makefile中)设置变量OS。还应该有一个可以自动定义OS的 shell 命令。如何使用编译器或 shell 设置OS-Variable?

亲切问候

C 预处理器只能比较整数值,而不能比较字符串或任何其他类型。当你编写#if OS == Linux时,预处理器首先展开宏OSLinux(以及它们扩展中的任何宏等)。完成扩展后,它将整行(#if本身之后)视为预处理器表达式并对其进行计算。与 C 语言本身一样,如果值为非零,则指令为 true,如果为 true,则像==这样的布尔运算符的计算结果为 1,如果为假,则计算结果为 0。

因此,要使#if OS == Linux正常工作,您必须为Linux选择一个数值(并为所有其他操作系统选择一个不同的值)。然后,您需要将OS分配给相同的值。例如,假设您有一个标头operating_systems.h包含

#define Linux 1
#define Darwin 2
#define Windows 3

然后,您可以使用#define OS 1#define OS (7 - 6)#define OS Linux或任何等效的方法来实现#if OS == Linux

请注意,如果LinuxDarwin未定义,并且您将OS定义为LinuxDarwin,则OS == LinuxOS == Darwin都将为 true,因为预处理器表达式中未定义的宏名称的值为 0。这种"类似枚举"的条件容易出错,因为未定义的值(或来自错误的"枚举"系列的值)不会被捕获,所以这不是一个好主意。

这是在操作系统之间进行选择的一种非常不寻常的方式。通常,系统选择基于是否定义了某些宏。例如,所有Linux编译器都应该定义__linux__,所有macOS编译器都应该定义__APPLE__,等等。要了解预定义的宏,请参阅编译器或操作系统的文档(包括适用的标准,例如 POSIX),或询问编译器(例如cpp -dM /dev/null)。

因此,典型的特定于操作系统的代码如下所示:

#if defined(__APPLE__)
// macOS or iOS code
#elif defined(__unix__)
// code for Unix-like systems
#  if defined(__linux__)
// additional code for Linux
#  endif
#elif defined(_WIN32) || defined(_WIN64)
// code for Windows
#else
#error "Unknown operating system"
#endif

如果需要在生成过程中选择无法单独由编译器确定的其他信息,则大多数编译器都有一种方法来预定义其他宏。在类Unix编译器(包括GCC,Clang和许多其他编译器)上,您可以通过在命令行上传递-DMACRO_NAME-DMACRO_NAME=expansion来实现这一点。例如,如果您使用

gcc -DPROTOCOL_VERSION=3

然后你可以像这样编写代码:

#if PROTOCOL_VERSION == 1
#error "Protocol version 1 is no longer supported."
#elif PROTOCOL_VERSION == 2
// code for version 2
#elif PROTOCOL_VERSION == 3
// code for version 3
#else
#error "An unsupported protocol version was requrested"
#endif

(此示例假定您的代码只能支持单个协议版本。

最新更新