在C中检测64位编译

Dan*_*iel 34 c unix linux gcc

是否有一个C宏或某种方式,我可以检查我的C程序是否在C编译时编译为64位或32位?

编译器:GCC我需要进行检查的操作系统:Unix/Linux

如果操作系统能够64位,我怎么能检查运行我的程序?

Ano*_*mie 35

既然你标记了这个"gcc",试试吧

#if __x86_64__
/* 64-bit */
#endif
Run Code Online (Sandbox Code Playgroud)

  • 另一个要测试的宏是'_____LP64_____',它可以在非x86-64架构上运行. (15认同)
  • @R ..:不,这几乎肯定是*正确的答案.以`_ [AZ]`或`__`开头的宏由实现(即编译器/预处理器)保留,这意味着您无法自己定义它们,但您当然可以测试它们的存在以查询实现. (10认同)
  • 仅适用于x86-64,而不适用于64位SPARC或PowerPC. (7认同)
  • @R ..:OTOH,C99标准保证uintptr_t足够大以容纳指针,但它不能保证它不大于所需的值.即使所有指针都是32位,实现也可以使用64位uintptr_t.或者,就此而言,由于uintptr_t在C99中是可选的,因此无论如何都可能无法定义"标准"宏. (4认同)
  • 测试任何以`_ [AZ]`或`__`开头的宏几乎肯定是错误的答案. (2认同)
  • @Adam:结果只会对某些实现有意义。如果您改为测试像`UINTPTR_MAX`这样的*标准*宏,它在所有实现中都是可靠的。(提示:一个有效的实现可以愉快地在 32 位机器上预定义 `__LP64__`,或者作为一个更极端的例子,它可以将 **all** 以 `__` 开头的宏名称视为已定义,除非它们明确未定义。 ) (2认同)
  • 我投反对票。原因请看我的回答。一般来说,这些场景都不能可靠地指示 64 位地址空间和非模拟 64 位算术是否可用,因此它们基本上是无用的,除非在不可用的构建系统的上下文中。不可知论者。因此,最好设置构建宏,以便构建系统可以选择编译哪个变体。 (2认同)

R..*_*R.. 25

这是正确的便携式测试,它不假设x86或其他任何东西:

#include <stdint.h>
#if UINTPTR_MAX == 0xffffffff
/* 32-bit */
#elif UINTPTR_MAX == 0xffffffffffffffff
/* 64-bit */
#else
/* wtf */
#endif
Run Code Online (Sandbox Code Playgroud)

  • 我知道这个问题是针对 C 的,但是因为它经常与 C++ 混合(或包含在 C++ 中),所以这里有一个 C++ 警告:C99 要求获得 C++ 中定义的限制宏,你必须有`__STDC_LIMIT_MACROS`在包含标题之前定义。由于它可能已经包含在内,确保正确定义的唯一方法是强制客户端始终将其作为源文件中的第一个标头包含,或者将 `-D__STDC_LIMIT_MACROS` 添加到所有文件的编译选项中。 (2认同)
  • 从理论上来说,可移植性受到uintptr_t是可选类型这一事实的限制。我怀疑对于64位实现忽略它是不正确的,因为`unsigned long long`是足够大的整数类型。 (2认同)
  • 这在Linux PAE内核上不起作用。激活了PAE的内核为32位,但可以像64位系统一样寻址RAM。该代码通过检查最大可寻址RAM来确定体系结构。32位PAE内核计算机将被视为64位,因此插入的源代码(可能有一些内联汇编程序指令)将无法工作。 (2认同)
  • 从我的角度来看,任何可以本地执行64位算术的体系结构都是64位体系结构。并且有几种架构仅具有24位地址总线,但由于其寄存器为32位,因此仍称为“ 32位”。与8位MCU相同,尽管它们的地址总线通​​常为14至16位或更多 (2认同)

Pat*_*ter 11

一个容易使语言律师得到解决的问题.

if(sizeof (void *) * CHARBIT == 64) {
...
}
else {
...
}
Run Code Online (Sandbox Code Playgroud)

由于它是一个常量表达式,优化编译器将丢弃测试并仅将正确的代码放入可执行文件中.

  • 它通常是真的,但是请,请停止做出"......所以优化编译器将......"这样的断言.预处理器是预处理器,当条件为真时,"else"之后的代码通常不会编译. (2认同)
  • 我不知道预处理器与任何东西有什么关系?OP要求一种方法来检测所使用的mem模型(64或32位),他没有要求预处理器解决方案.没有人问过一种方法来取代条件编译.当然,我的解决方案要求两个分支在语法上都是正确的.编译器将始终编译它们.如果编译器正在优化它将删除生成的代码,但即使它没有,也没有问题.注意详细说明你的意思? (2认同)
  • @ShelbyMooreIII:嗯...对不起?32位与64位目标的区别与`int`的大小完全无关(实际上,它的大小_differs_例如在LP64中用于Linux/BSD与Windows中使用的LLP64,而两者都是非常清楚64位).它也与编译器优化特定操作的速度(或Javascript执行速度有多快)无关. (2认同)
  • 不检测64位体系结构上的ILP32 ABI,例如[Linux x32 ABI](https://en.wikipedia.org/wiki/X32_ABI)或[AArch64 ILP32 ABI](http://infocenter.arm. COM /帮助/ index.jsp的?主题=/com.arm.doc.dai0490a/ar01s01.html).这是64位模式下的32位指针.所以`long long`在这些目标上仍然有效,不像32位CPU,其中64位整数每个操作需要2个指令,以及2个寄存器. (2认同)

Dar*_*ust 8

编译器和平台中立的解决方案是这样的:

// C
#include <stdint.h>

// C++
#include <cstdint>

#if INTPTR_MAX == INT64_MAX
// 64-bit
#elif INTPTR_MAX == INT32_MAX
// 32-bit
#else
#error Unknown pointer size or missing size macros!
#endif
Run Code Online (Sandbox Code Playgroud)

避免以一个或多个下划线开头的宏。它们不是标准的,可能会在您的编译器/平台上丢失。


Ale*_*x B 5

使用特定于编译器的宏.

我不知道您的目标是什么架构,但由于您没有指定它,我将假设一般的英特尔机器,因此您很可能对测试Intel x86AMD64感兴趣.

例如:

#if defined(__i386__)
// IA-32
#elif defined(__x86_64__)
// AMD64
#else
# error Unsupported architecture
#endif
Run Code Online (Sandbox Code Playgroud)

但是,我更喜欢将它们放在单独的头文件中并定义我自己的编译器中立宏.

  • @R ..在64位Windows上它仍然是错误的.我更喜欢我的代码无法编译,而不是默默地编译错误的东西. (3认同)