以64位可执行文件执行64位计算

时间:2016-09-16 07:26:40

标签: c++ c++11 64-bit x86-64 integer-overflow

我正在使用带有Code :: Blocks的MinGW64(带有-m64标志),并希望知道如何执行64位计算而不必使用以下内容:

int64_t test = int64_t(2123123123) * 17;

如果我使用它,计算溢出并返回1733354723,它应该返回36093093091:

int64_t test = 2123123123 * 17;

我已将我的可执行文件上传到病毒总数,证实我的可执行文件是x64。

编辑:应该提到我在Windows 7 x64上。

5 个答案:

答案 0 :(得分:4)

即使在64位编译中,默认的int类型仍然是32位,用于兼容性调整。

我猜的“最短”版本是将ll后缀添加到数字

int64_t test = 2123123123ll * 17;

另一种方法是将数字存储在自己的int64_t(或long long)变量中,然后乘以变量。通常,在程序中很少有很多“魔术数字”硬编码到代码库中。

答案 1 :(得分:4)

一些背景:

曾几何时,大多数计算机都有8位算术逻辑单元和16位地址总线。我们称它们为8位计算机。

我们学到的第一件事就是没有现实世界的算术问题可以用8位表示。这就像试图利用黑猩猩的算术能力推理太空飞行一样。因此,我们学会了编写多字加,乘,减和除序列。因为在大多数现实问题中,问题的数值域大于255。

我们简单地使用了16位计算机(其中应用了相同的问题,65535仅仅不足以模拟事物),然后非常快,内置于芯片的32位算术逻辑。渐渐地,地址总线赶上了(20位,24位,32位,如果设计师感到奢侈的话)。

然后发生了一件有趣的事情。我们大多数人不再需要编写多字算术序列。事实证明,大多数(tm)现实世界的整数问题可以用32位(最多40亿)表示。

然后我们开始以比以往更快的速度生成更多数据,并且我们认为需要处理更多内存。 64位计算机最终成为常态。

但是,大多数现实世界的整数算术问题都可以用32位表示。对于大多数事情来说,40亿是一个很大(足够)的数字。

因此,大概通过统计分析,您的编译器编写者决定在您的平台上,int的最有用大小是32位。对于32位算术(我们从第1天开始需要),任何更小的算法都是低效的,任何更大的算法都会浪费空间/寄存器/内存/ cpu周期。

在c ++(和c)中表达整数文字会产生一个int - 环境的自然算术大小。在今天,这几乎总是32位值。

c ++规范说,乘以两个整数会产生一个int。如果它没有,那么乘以两个整数就需要产生一个长期。但那么两个多头产量会增加多少呢?好久不见?好的,这是可能的。现在,如果我们乘以那些呢?很长很久很长?

这就是那个。

int64_t x = 1 * 2;将执行以下操作:

  1. 取值1的整数(32位)。
  2. 取值为2的整数(32位)。
  3. 将它们相乘,将结果存储为整数。如果算术溢出,那就这样吧。那是你的了望。
  4. 将生成的整数(无论现在是什么)强制转换为int64(可能在您的系统上long int
  5. 所以简而言之,不。在问题的代码片段中没有拼写出至少一个操作数类型的快捷方式。当然,您可以指定文字。但是不能保证系统上的long long(LL文字后缀)与int64_t相同。如果您想要int64_t,并且希望代码可移植,则必须将其拼写出来。

    为了它的价值:

    在后c ++ 11世界中,所有对额外击键和非干扰的担忧都会消失:

    绝对是int64:

    auto test = int64_t(2123123123) * 17;
    

    肯定是漫长的一段时间:

    auto test = 2'123'123'123LL * 17;
    

    绝对是int64,肯定是用一个(可能缩小,但没关系)长期初始化:

    auto test = int64_t(36'093'093'091LL);
    

答案 2 :(得分:3)

由于您最有可能处于LP64环境中,int只有32位,因此您必须注意表达式中的文字常量。最简单的方法是养成在文字常量上使用正确后缀的习惯,因此你可以将上面的内容写成:

int64_t test = 2123123123LL * 17LL;

答案 3 :(得分:2)

2123123123int(通常是32位)。

添加L使其成为long2123123123L(通常为32位或64位,即使在64位模式下)。

添加另一个L使其成为long long2123123123LL(64位或更多,从C ++ 11开始)。

请注意,您只需要将后缀添加到超出int大小的常量。积分转换将产生正确的结果*。

(2123123123LL * 17)  // 17 is automatically converted to long long, the result is long long

*但要注意:即使表达式中的各个常量适合int整个操作仍然会像

一样溢出
(1024 * 1024 * 1024 * 10)

在这种情况下,您应确保以足够的宽度执行算术运算(考虑运算符优先级):

(1024LL * 1024 * 1024 * 10)

- 将以64位执行所有3个操作,结果为64位。

答案 4 :(得分:1)

编辑:文字常量(A.K.A.魔术数字)不受欢迎,因此最好的方法是使用符号常量(const int64_t value = 5)。有关详细信息,请参阅What is a magic number, and why is it bad?最好不要阅读本答案的其余部分,除非你真的想因某些奇怪的原因使用魔法数字。

此外,您可以使用intptr_t中的uintprt_t#include <cstdint>让编译器选择是使用int还是__int64

<德尔> 对于那些偶然发现这个问题的人来说,数字末尾的“LL”可以解决这个问题,但是不建议这样做,因为理查德·霍奇斯告诉我,“long long”可能并不总是64位,并且可以增加未来的规模,虽然不太可能。有关更多信息,请参阅Richard Hodge的回答及其评论。

<德尔> 可靠的方法是将`使用QW = int_64t;`放在顶部并使用`QW(5)`而不是'5LL`。

<德尔> 我个人认为应该有一个选项来定义64位的所有文字,而不必向它们添加任何后缀或函数,并在必要时使用`int32_t(5)`,因为某些程序不受此更改的影响。示例:仅使用数字进行正常计算,而不是依靠整数溢出来完成它的工作。问题是从64位变为32位,而不是从32位变为64位,因为前4个字节被切断。