【问题标题】:Conditional compilation in system header files系统头文件中的条件编译
【发布时间】:2015-01-19 03:00:57
【问题描述】:

系统头文件中的条件编译(如<sys/types.h>)如何控制编译过程的问题让我困惑了很久 例如,这是<sys/types.h> 中一个常见的 typedef 代码片段:

#  if __WORDSIZE == 64
typedef long int int64_t;
#  elif __GLIBC_HAVE_LONG_LONG
__extension__ typedef long long int int64_t;
#  endif
# endif

也就是说,如果__WORDSIZE == 64,那么我们将类型int64_t定义为long int的一个别名,但我想知道在哪里可以找到__WORDSIZE的定义。

  • __WORDSIZE 的宏是否已在某个文件中静态定义?如果 那么,这个文件是如何生成的呢?
  • 或者,我们将预处理器宏传递给编译器?
  • 或者,编译器知道它运行在什么样的机器上?但它是怎么知道的呢?

毕竟要怎么写一个头文件才能达到下面的意图:

#if the machine is 64-bit
typedef unsigned long int KEY_TYPE
#elif the machine is 32-bit
typedef unsigned long long int KEY_TYPE
#endif

【问题讨论】:

    标签: c++ linux architecture conditional-compilation


    【解决方案1】:

    这取决于编译器和系统。它 (__WORDSIZE) 可能由编译器定义为内置宏(可能会根据编译器选项而改变),或者它可能位于系统头文件中。阅读系统标题充其量是艰苦的工作。一般来说,你不应该试图猜测其中的内容。

    请注意,__WORDSIZE 位于为实现保留的命名空间中。只要它正常工作,实现就可以随心所欲。如果将代码绑定到__WORDSIZE,则在更改编译器版本、编译器品牌、操作系统版本、操作系统品牌时可能会遇到问题。

    至于编译器如何检测它所在的系统:那是编译器的问题。它旨在为特定系统(通常是主机系统,除非它是交叉编译器)生成代码。编译器设置为知道如何正确编译代码;如何创建 32 位目标代码或程序,以及如何创建 64 位目标代码或程序。如果它不知道如何正确创建代码,它作为编译器就没有多大用处,不是吗?

    您可以通过以下方式实现您的目标:

    // #include <stdint.h> // C header
    #include <cstdint>     // C++ analogue of <stdint.h>
    
    typedef uint64_t KEY_TYPE;
    

    代码中没有条件编译——这是编写代码的最佳方式。

    警告:从技术上讲,uint64_t 是一种可选类型。但是,无论它不可用,您都会遇到问题。)

    【讨论】:

    • 谁控制编译器选项?你的意思是编译器会根据它安装的计算机类型给 __WORDSIZE 不同的定义?但是,编译器怎么知道机器的特性呢?是否需要我们手动提供这些功能选项?但我不记得我在我的机器上安装 gcc 编译器时这样做了。
    • 在我的机器上,我最常使用 GCC。我可以使用gcc -m64 生成64 位目标代码和gcc -m32 生成32 位代码,每次都运行相同的编译器。如果我尝试在 Linux 机器上使用 Mac OS X 的编译器,它不会运行,反之亦然,所以是的,编译器知道它安装在哪种机器类型上。构建为 64 位二进制文​​件的编译器也不会在仅支持 32 位二进制文​​件的机器上运行。因此,您(运行编译器的人)控制编译器选项,尽管如果您不覆盖它们,编译器将使用默认值。
    • 对了,我也想知道系统头文件和gcc编译器头文件的关系。它们之间是否存在依赖关系?以及,谁创建了系统头文件?安装Linux操作系统的过程中是否总是包含系统头文件的创建?
    • GCC 尽可能使用系统头文件,但它包含一个步骤fixincludes,它修复了它在系统头文件中发现的各种问题,创建了它自己的麻烦系统头文件的私有变体。系统标头由构建系统的人员提供。有些是内核头文件;有些不是。那些没有的可能随系统的 C 库一起提供。安装 Linux 不一定要安装系统头文件。您必须安装开发系统(C编译器和相关包)才能获得核心头文件,以及特定的包才能获得相应的头文件。
    【解决方案2】:

    要发现 gcc 内置定义(在编译任何文件之前)尝试使用:

    gcc -std=c++11 -E -P -v -dD temp.cpp

    (temp.cpp 只需为空文件)

    将 -std=c++11 更改为您需要的标准。

    其中一些内置定义将用于控制系统头文件的编译。

    一些内置定义仅供内部(对 gcc)使用。您需要查阅 gcc 文档以了解您可以在您的 gcc 版本中使用哪些内置定义。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-26
      • 2010-10-28
      • 1970-01-01
      • 2019-06-05
      • 2012-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多