我必须使用大量#ifdef i386 和 x86_64 来处理特定于架构的代码,有时还要使用#ifdef MAC 或#ifdef WIN32… 等等来处理特定于平台的代码。
我们必须保持通用代码库和可移植性。
但是我们必须遵循#ifdef 的使用是严格不的准则。我不明白为什么?
作为这个问题的扩展,我还想了解何时使用 #ifdef ?
例如,dlopen() 在从 64 位进程运行时无法打开 32 位二进制文件,反之亦然。因此它的架构更具体。我们可以在这种情况下使用#ifdef 吗?
原文由 RLT 发布,翻译遵循 CC BY-SA 4.0 许可协议
使用
#ifdef
而不是编写可移植代码,您仍在编写多段特定于平台的代码。不幸的是,在许多(大多数?)情况下,您很快就会得到一个几乎难以理解的可移植代码和特定于平台的代码的混合体。您还经常得到
#ifdef
用于除可移植性之外的其他目的(定义要生成的代码的“版本”,例如将包括什么级别的自我诊断)。不幸的是,两者经常互动,并交织在一起。例如,将一些代码移植到 MacOS 的人认为它需要更好的错误报告,他补充道——但使其特定于 MacOS。后来,其他人认为更好的错误报告在 Windows 上会非常有用,所以他通过自动启用该代码#define
如果定义了 WIN32 则使用 MACOS ——但随后添加“只是多一些”#ifdef WIN32
在定义 Win32 时 排除一些真正特定于 MacOS 的代码。当然,我们还添加了 MacOS 基于 BSD Unix 的事实,因此在定义 MACOS 时,它也会自动定义 BSD_44 ——但是(再次)转过身来,在为 MacOS 编译时 排除 了一些 BSD“东西”。这很快就会退化为如下示例的代码(取自 #ifdef Considered Harmful ):
这是一个很小的例子,只涉及到 几个 宏,但是阅读代码已经很痛苦了。我个人在实际代码中看到(并且不得不处理) 更 糟糕的情况。这里的代码很难看而且读起来很痛苦,但是仍然很容易弄清楚在什么情况下将使用哪些代码。在许多情况下,您最终会得到更复杂的结构。
举一个具体的例子来说明我希望如何看到它,我会做这样的事情:
在这种情况下,我们对 loggerr 的定义 可能 是一个宏而不是一个实际的函数。它可能是微不足道的,有一个像这样的标题是有意义的:
[目前,假设预处理器可以/将处理可变参数宏]
考虑到你的主管的态度,即使这样 也可能 是不可接受的。如果是这样,那很好。取而代之的是宏,而是在函数中实现该功能。将函数的每个实现隔离在其自己的源文件中,并构建适合目标的文件。如果您有很多特定于平台的代码,您通常希望将其隔离到它自己的目录中,很可能使用它自己的 makefile 1 ,并拥有一个顶级 makefile,它只根据指定的目标。