#ifdef 用于 32 位平台
Posted
技术标签:
【中文标题】#ifdef 用于 32 位平台【英文标题】:#ifdef for 32-bit platform 【发布时间】:2010-10-18 15:36:48 【问题描述】:在我维护的一个应用程序中,我们遇到了影响标准库的文件描述符限制问题。此问题仅影响 32 位版本的标准库。
我已经为我的代码设计了一个修复程序并希望实现它,但仅限于为 32 位可执行文件编译时。 #ifdef 可以使用什么预处理器符号来确定代码是针对 32 位还是 64 位目标编译的?
编辑
不好意思,没提,代码是跨平台的,linux、windows、solaris等几个unix风格,主要是用GCC编译。我可以跨平台使用任何事实上的标准吗?
编辑 2
我发现了一些定义“__ILP23”和“__LP64”,它们似乎可以工作......here 的讨论解释了 unix 平台的背景。有人有使用这些定义的经验吗?这个可以用吗?
【问题讨论】:
这取决于平台。不同的操作系统使用不同的#defines。如果你幸运的话,Boost 有一个隐藏在某个地方的便携式包装器。但除此之外,您只需要检查特定于平台的那些。顺便问一下,您在哪个平台上运行? 编辑了问题...代码主要针对 windows、solaris 和 linux,部分还运行在 AIX 和 HP-UX 上。 只是一个想法:#if sizeof(int) == 64 @rstevens:我认为以下答案之一中的 cmets 表示 #if 和 sizeof(int) 是在不同时间执行的。当预处理器完成其工作时,sizeof 运算符尚未执行。 见***.com/questions/152016/… 【参考方案1】:我会通过最大指针值常量间接测试它:
#include <stdint.h>
#if UINTPTR_MAX == 0xffFFffFF
// 32-bit platform
#elif UINTPTR_MAX == 0xffFFffFFffFFffFF
// 64-bit platform
#else
#error Unknown platform - does not look either like 32-bit or 64-bit
#endif
这样您就不会依赖于任何特定于平台的架构定义,而是依赖于具有特定架构的直接后果 - 指针大小。
【讨论】:
如果您使用 C++11,那么您可以检查宏SIZE_MAX
的值,这是 std::size_t
类型变量可以容纳的最大值。在 32 位平台上为 0xFFFFFFFF
,在 64 位平台上为 0xFFFFFFFFFFFFFFFF
。宏在标题<cstdint>
中提供。【参考方案2】:
我在 Windows 上使用这样的结构:
#如果定义(_WIN64) //64位代码 #elif 定义(_M_IX86) //32位代码 #别的 #error "未知平台" #万一对比:
#如果定义(_WIN64) // 64位代码 #别的 // 32 位代码 #万一在前一种解决方案中,由于#error,编译器将能够告诉您需要在哪里为新平台添加代码。如果您遇到既不是 64 位也不是 32 位的平台,这有助于可维护性。是的,_M_IX86 并不完全是 32 位的同义词,但我认为我们大多数人支持的唯一 32 位平台实际上是 x86。所以作为一个实际的措施就足够了。
在后面的解决方案中,您必须使用 grep 或类似的工具手动确定新平台需要代码的位置。这是乏味且容易出错的。
我想到下面的结构也是可以接受的,虽然我没有在生产中测试过,也没有真正考虑过。
#如果定义(_WIN64) //64位代码 #elif 定义(_WIN32) //32位代码 #别的 #error "未知平台" #万一【讨论】:
【参考方案3】:我建议将predef SourceForge 加入书签。没有唯一的答案,但它肯定可以帮助您入门。
编辑:对于仅限 GCC 的代码,您可以使用 __i386__
来检查 32 位 x86 芯片,我建议尝试使用 __X86_64__
或类似的东西来检查 64 位 x86 芯片。 (注意:我注意到之前涉及__ia86__
的答案实际上是一个不同的芯片,而不是64位x86芯片。这只是表明我缺乏硬件经验。对于那些比我更了解硬件的人,领事我在上面链接到的关于预定义宏的 SourceForge 页面。它比我更准确。)还有一些其他的可以工作,但是这两个在 GCC 版本中应该是相当普遍的。
【讨论】:
ia64 是否适用于普通的 intel64 位编译?或者有没有amd64之类的? 我没有使用 64 位架构(或在非英特尔架构上编程)的经验,但根据 predefs 页面,有一个 64 位的 amd64 AMD。 ia64 似乎是特定于 x86 的。 i386 仅在为 intel cpu 编译时才有效,对吗?在 solaris 上,我们为 sparc-s2 编译。 作为另一个提示,你可以运行gcc -E -dM - </dev/null
(或者离开</dev/null
,在你按下回车键后输入EOF),GCC 会输出一个它包含的所有宏的列表-定义。在几个平台上执行此操作,并为每个平台编制一份独特且有用的列表。
@veefu - 是的,SPARC 芯片会有不同的宏。最有可能的是,您可以使用 sparc 或类似的东西。对于每个平台,您可以使用大约三个相似但不同的宏,尤其是对于 GCC。检查预定义页面。【参考方案4】:
至少 32 位 Solaris 有 256 个文件指针的限制,因为该结构将文件描述符存储在无符号字符字段中。保留这一点是为了向后兼容一些几乎不可能的旧版本 SunOS。其他平台——我想说大多数其他平台——没有这个限制。另一方面,普通用户程序需要同时打开这么多文件是比较少见的。它通常表示一个错误(完成后不关闭文件)而不是。话虽如此,但对于需要同时打开大量数据文件的数据库服务器来说,这可能是个问题。
一条评论说:
差不多了。我们没有打开大量文件,但服务器处理了大量来自客户端的连接。套接字句柄和文件描述符似乎来自同一个地方。当我们有很多连接时,'fopen' 会失败,因为系统级调用返回并且 fd > 255。
“套接字句柄”是系统调用级别的文件描述符,因此它们与文件的常规文件描述符来自同一位置。
如果你必须解决这个问题,那么你需要包装你当前的套接字打开代码,这样如果它得到一个 0..255 范围内的文件描述符,那么它会调用 'dup2()
' 来创建一个文件描述符在 stdio 不会使用的范围内 - 然后关闭原始文件描述符。唯一的问题是您必须跟踪哪些文件描述符可用,因为dup2
将愉快地关闭目标文件描述符,如果它当前是打开的。
当然,我假设您的套接字代码读取文件描述符而不是文件指针。如果是这样的话,你的问题就更大了——太多的东西想要使用相同的资源,而它们不能同时使用它们。
【讨论】:
差不多了。我们没有打开大量文件,但服务器处理了大量来自客户端的连接。套接字句柄和文件描述符似乎来自同一个地方。当我们有很多连接时,'fopen' 会失败,因为系统级调用返回并且 fd > 255。 是的,这几乎就是我已经实现的。使用调用 'fcntl' 的代码包装对 'socket' 和 'accept' 的调用以在 【参考方案5】:您可以检查一个众所周知的类型的大小,例如sizeof(int*) == 4 对于 32 位平台。
由于 sizeof 在编译时是已知的,我相信
if(sizeof(int*) == 4)
...
应该做的伎俩
编辑:cmets 是正确的,您需要使用常规 if,#if 将不起作用。
如果您使用 C++,您可以创建模板代码并让编译器根据 sizeof() 调用为您选择专业化。 如果您为 32 位平台构建,编译器只会实例化 32 位平台的代码。 如果为 654 位平台构建,编译器只会实例化 64 位平台的代码。
【讨论】:
这不适用于#ifdef。 sizeof 是编译时间,而 #if 是预处理器时间 同意。在 OS X Leopard 上的 GCC 4.0.1 上测试。 创建一个程序,作为构建过程的一部分运行测试,并将一些#defines输出到配置文件或Makefile中? 这将在同一个可执行文件/库中包含 32 位和 64 位代码。我不喜欢这种方法,因为它依赖于 4 或任何字节长的指针。不好的做法。 如果您只为 32 位平台构建,编译器只会实例化 32 位平台的代码。如果指针是 4 字节或 8 字节,则依赖关系的全部意义在于区分 32 位和 64 位平台【参考方案6】:我不确定是否有合适的通用#if def。 C++ 标准几乎肯定没有定义一个。当然也有特定平台的。
例如,Windows
#if _WIN64
// 64 bit build
#else
// 32 bit build
#endif
EDIT OP 提到这是使用 GCC 和其他编译器在 Windows 和非 Windows 之间进行的交叉编译
没有可用于所有平台和编译器的通用宏。一点预处理器的魔法虽然可以做到这一点。假设您只在 x86 和 amd64 芯片上工作,以下应该可以解决问题。不过,它可以很容易地扩展到其他平台
#if _WIN64 || __amd64__
#define PORTABLE_64_BIT
#else
#define PORTABLE_32_BIT
#endif
【讨论】:
好吧,听起来像这样,结合 Chris 的 cmets 进行的一些 gcc 调查可能会奏效。 +1 你们俩。【参考方案7】:看看那个:
i386 macrosAMD64 macros
【讨论】:
【参考方案8】:我最终可能会在 Makefile 中使用 uname 确定您是在 32 位平台还是 64 位平台上。然后,添加到您的 CFLAGS、-DX32 或 -DX64。你可以#ifdef X64。
但这只是一个统一的解决方案。我不确定我会在 Windows 上做什么。
【讨论】:
这样做的问题是,即使用于编译的系统是 64 位的,它也可能正在编译一个 32 位的可执行文件。不过,您是对的,这些信息必须以某种方式在 makefile 中公开。编译器必须被告知目标是 32 还是 64。应该能够适应。【参考方案9】:C++ 标准没有定义这样的符号 - 您的特定平台(您的问题中没有指定)可能会提供一个。
【讨论】:
【参考方案10】:取决于您的操作系统和编译器,这些是实施决策。
【讨论】:
【参考方案11】:我相信定义是_WIN64
【讨论】:
以上是关于#ifdef 用于 32 位平台的主要内容,如果未能解决你的问题,请参考以下文章