23

在我维护的一个应用程序中,我们遇到了影响标准库的文件描述符限制的问题。此问题仅影响 32 位版本的标准库。

我已经为我的代码设计了一个修复程序并希望实现它,但仅限于编译 32 位可执行文件时。#ifdef 可以使用什么预处理器符号来确定代码是针对 32 位还是 64 位目标编译的?

编辑

不好意思,没提,代码是跨平台的,linux,windows,solaris等几个unix风格,主要是用GCC编译。我可以跨平台使用任何事实上的标准吗?

编辑 2

我发现了一些定义“__ILP23”和“__LP64”,它们似乎可以工作......这里的讨论解释了unix平台的背景。有人有使用这些定义的经验吗?这能用吗?

4

11 回答 11

18

我不确定是否有一个合适的通用#if def。C++ 标准几乎肯定没有定义一个。当然有平台特定的。

例如,Windows

#if _WIN64 
// 64 bit build
#else
// 32 bit build
#endif

编辑OP 提到这是使用 GCC 和其他编译器在 Windows 和非 Windows 之间进行的交叉编译

没有可用于所有平台和编译器的通用宏。一点预处理器的魔法虽然可以做到这一点。假设您只在 x86 和 amd64 芯片上工作,以下应该可以解决问题。虽然它可以很容易地扩展到其他平台

#if _WIN64 || __amd64__
#define PORTABLE_64_BIT
#else
#define PORTABLE_32_BIT
#endif
于 2009-04-09T19:43:02.573 回答
15

我建议为predef SourceForge 添加书签。没有一个答案,但它肯定可以帮助您入门。

编辑:对于仅限 GCC 的代码,您可以使用它__i386__来检查 32 位 x86 芯片,我建议尝试__X86_64__或类似的东西来检查 64 位 x86 芯片。(注意:我注意到之前的答案涉及__ia86__的实际上是不同的芯片,而不是 64 位 x86 芯片。这只是表明我缺乏硬件经验。对于那些比我更了解硬件的人,请咨询 SourceForge 页面在我链接到上面的预定义宏上。它比我更准确。)还有一些其他的可以工作,但是这两个在 GCC 版本中应该是相当普遍的。

于 2009-04-09T19:45:02.460 回答
6

看看那个:

i386 宏
AMD64 宏

于 2009-04-09T19:53:51.050 回答
6

我会通过最大指针值常量间接测试它:

#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

这样,您不依赖于任何特定于平台的架构定义,而是依赖于具有特定架构的直接后果 - 指针大小。

于 2019-01-16T17:13:25.887 回答
5

您可以检查一个众所周知的类型的大小,例如 sizeof(int*) == 4 用于 32 位平台。

由于 sizeof 在编译时已知,我相信

if(sizeof(int*) == 4)
{
  ...
}

应该做的伎俩

编辑:评论是正确的,你需要使用常规的 if,#if 不起作用。

如果您使用 C++,您可以创建模板代码并让编译器根据 sizeof() 调用为您选择专业化。如果您为 32 位平台构建,编译器只会实例化 32 位平台的代码。如果您为 654 位平台构建,编译器只会实例化 64 位平台的代码。

于 2009-04-09T19:43:02.840 回答
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 "未知平台"
#万一
于 2011-07-23T13:33:32.597 回答
2

我最终可能会做的是在 Makefile 中,使用 uname 确定您是在 32 位平台上还是 64 位平台上。然后,添加到您的 CFLAGS、-DX32 或 -DX64。你可以只用#ifdef X64。

但这只是一个统一的解决方案。我不确定我会在 Windows 上做什么。

于 2009-04-09T19:51:58.760 回答
2

至少 32 位 Solaris 有 256 个文件指针的限制,因为该结构将文件描述符存储在无符号字符字段中。保留这一点是为了向后兼容一些几乎不可能的旧版本 SunOS。其他平台——我想说大多数其他平台——没有这个限制。另一方面,一个普通的用户程序需要同时打开这么多文件是比较少见的。它通常表示一个错误(完成后不关闭文件)而不是。尽管如此,对于需要同时打开大量数据文件的数据库服务器来说,这可能是个问题。


一条评论说:

差不多就是这样。我们没有打开大量文件,但服务器处理了大量来自客户端的连接。套接字句柄和文件描述符似乎来自同一个地方。当我们有很多连接时,'fopen' 会失败,因为系统级调用返回并且 fd > 255。

“套接字句柄”是系统调用级别的文件描述符,因此它们与文件的常规文件描述符来自同一位置。

如果你必须解决这个问题,那么你需要包装你当前的套接字打开代码,这样如果它得到一个 0..255 范围内的文件描述符,那么它会调用 ' dup2()' 在 stdio 赢得的范围内创建一个文件描述符'不使用 - 然后关闭原始文件描述符。唯一的障碍是您必须跟踪哪些文件描述符可用,因为dup2如果目标文件描述符当前打开,它将愉快地关闭它。

当然,我假设您的套接字代码读取文件描述符而不是文件指针。如果是这样的话,你就会遇到更大的问题——太多的东西想要使用相同的资源,而它们不能同时使用它们。

于 2009-04-09T20:11:49.727 回答
1

取决于您的操作系统和编译器,这些是实施决策。

于 2009-04-09T19:45:09.417 回答
0

我相信定义是_WIN64

于 2009-04-09T19:43:24.727 回答
0

C++ 标准没有定义这样的符号 - 您的特定平台(您没有在问题中指定)可能会提供一个。

于 2009-04-09T19:45:29.010 回答