__int64 在 32 位机器上?

Posted

技术标签:

【中文标题】__int64 在 32 位机器上?【英文标题】:__int64 on a 32-Bit machine? 【发布时间】:2011-02-11 03:34:46 【问题描述】:

我刚刚在我的 32 位机器上尝试了 MSVC 2010 中的一些东西,发现我可以在我的程序中使用 __int64 - 这确实有效!

这怎么可能?

【问题讨论】:

你甚至可以使用标准的 int64_t! @el.pescado: int64_t 仅在 C99 中是标准的;它目前不是 C++ 标准的一部分,但将在即将发布的 C++0x 中添加。 在实践中,您的 32 位机器(即 >Pentium)有一些原生的 64 位支持,它也有 36 位的地址空间。只是 Windows 选择将您限制为 32 位 阅读您的评论后,我反汇编了一个释放模式程序,该程序将 2 个 int64 值相乘,以查看它是否使用特殊指令。它没有。你确定 Pentium 支持 64 位算术吗? Well x86 指令集是为轻松链接 add、sub、mul 而设计的。不幸的是,虽然 64 位 div 乘以 32 位,但 64 位 div 的实现并不容易。 【参考方案1】:

32 位算法在 16 位系统上的工作方式相同。

在这种情况下,它使用 2 个 32 位的内存地址一起组成一个 64 位的数字。加法/减法很容易,你可以分部分来做,唯一的问题就是从较低的部分到较高的部分进行结转。对于乘法/除法,它更难(即更多指令)。

它显然很慢,比用于乘法的 32 位算术要慢很多,但如果你需要它,它就在那里。当您升级到 64 位 processor 编译器时,它会自动优化为具有更大字长的一条指令。

在发布模式下编译的 32 位处理器上的 64 位乘法的 Visual Studio 2010 Professional 实现是:

_allmul PROC NEAR

A       EQU     [esp + 4]       ; stack address of a
B       EQU     [esp + 12]      ; stack address of b

        mov     eax,HIWORD(A)
        mov     ecx,HIWORD(B)
        or      ecx,eax         ;test for both hiwords zero.
        mov     ecx,LOWORD(B)
        jnz     short hard      ;both are zero, just mult ALO and BLO

        mov     eax,LOWORD(A)
        mul     ecx

        ret     16              ; callee restores the stack

hard:
        push    ebx

A2      EQU     [esp + 8]       ; stack address of a
B2      EQU     [esp + 16]      ; stack address of b

        mul     ecx             ;eax has AHI, ecx has BLO, so AHI * BLO
        mov     ebx,eax         ;save result

        mov     eax,LOWORD(A2)
        mul     dword ptr HIWORD(B2) ;ALO * BHI
        add     ebx,eax         ;ebx = ((ALO * BHI) + (AHI * BLO))

        mov     eax,LOWORD(A2)  ;ecx = BLO
        mul     ecx             ;so edx:eax = ALO*BLO
        add     edx,ebx         ;now edx has all the LO*HI stuff

        pop     ebx

        ret     16              ; callee restores the stack

如您所见,它比普通乘法慢很多。

【讨论】:

不管你有什么处理器,除非你为 x64 编译,否则它不会得到优化。 在 C# 中会是真的!【参考方案2】:

为什么你会感到惊讶?没有什么可以阻止编译器在 32 位机器上支持 64、128 或更多位的整数类型。如果愿意,编译器甚至可以支持 57 位和 91 位类型。实际上,在 N 位机器上支持 2N 位整数运算是一项相对容易的任务,因为典型机器的指令集通常在设计时考虑到这种功能。

【讨论】:

【参考方案3】:

32位只是一个机器字的原生大小,意味着它们可以一次性处理,并不意味着更大的项目根本无法处理,它们只需要作为单独的32位处理多个步骤中的单元,以同样的方式,它们可以小于机器字,在这种情况下,只会处理整个机器字的一部分。

【讨论】:

【参考方案4】:

之所以有效,是因为 64 位整数数据类型是语言规范的一部分

该语言的编译器必须允许您使用 64 位整数(当然,并获得正确的结果)。

无论您的目标是 64 位、32 位、16 位还是 8 位机器(无论编译器允许什么),您的程序都必须工作(并且工作完全相同)。

编写编译器的人有义务使其做任何需要以使每个支持的数据类型在每个目标处理器类型上工作。

支持可能“更高”的数据类型已全部处理完毕,因此您不必自己动手。

怎么做?

显然,接受命令 16 位算术运算的代码并将其转换为在 16 位(或更高)处理器上运行的机器代码对于编译器来说是“容易”的工作,几乎是直接翻译。 Z = X + Y 可能会转换为 mov a,(X); add a,(Y); mov (Z),a;

相反,接受命令 64 位算术运算的代码并将其转换为在 32 位(或更低)处理器上运行的机器代码更为复杂。编译器有更多工作要做,一次对每个操作数的 32 位片段进行操作。还有更多方法可以完成。

生成的机器代码可以使用多条内联指令(更大的代码,更快的执行)。 Z = X + Y 可能会转换为 mov a,(X); adc a,(Y); mov (Z),a; mov a,CARRY; adc a,(X+1); adc a,(Y+1); mov (Z+1),a;

生成的机器代码可以调用扩展的算术子例程(代码更小,执行速度更慢)。 Z = X + Y 可能会转换为 mov a,X; call GET64; mov a,Y; call ADD64; mov a,Z; call STORE64;

【讨论】:

您的主要观点不正确。 C++ 标准不要求实现支持 64 位整数类型。 非常感谢。也许这是事实。 自 C99 起 指定类型:[signed] long long [int]:64 位。范围:[−9,223,372,036,854,775,807, +9,223,372,036,854,775,807](−9,223,372,036,854,775,808 可选)。无符号长长 [int]:64 位。范围:[0, +18,446,744,073,709,551,615]。 en.wikipedia.org/wiki/C_data_types.

以上是关于__int64 在 32 位机器上?的主要内容,如果未能解决你的问题,请参考以下文章

64位 regsrv win10_Regsvr32 在64位机器上的用法

64位机器上的结构填充

Linux中32位和64位数据类型长度都有哪些不同

int,int32_t,int64_t

int,int32_t,int64_t

_mm_crc32_u64 定义不明确