【问题标题】:long long vs int multiplicationlong long vs int 乘法
【发布时间】:2010-08-16 18:31:01
【问题描述】:

给定以下 sn-p:

#include <stdio.h>

typedef signed long long int64;
typedef signed int int32;
typedef signed char int8;

int main()
{
    printf("%i\n", sizeof(int8));
    printf("%i\n", sizeof(int32));
    printf("%i\n", sizeof(int64));

    int8 a = 100;
    int8 b = 100;
    int32 c = a * b;
    printf("%i\n", c);

    int32 d = 1000000000;
    int32 e = 1000000000;
    int64 f = d * e;
    printf("%I64d\n", f);
}

MinGW GCC 3.4.5 的输出是 (-O0):

1
4
8
10000
-1486618624

第一个乘法在内部转换为 int32(根据汇编器输出)。第二个乘法没有强制转换。我不确定结果是否不同是因为程序在 IA32 上运行,还是因为它是在 C 标准中的某个地方定义的。不过,如果在某处定义了这种确切的行为(ISO/IEC 9899?),我很感兴趣,因为我想更好地理解为什么以及何时必须手动转换(我在从不同架构移植程序时遇到问题)。

【问题讨论】:

    标签: c multiplication long-long


    【解决方案1】:

    C99 标准确实指定二元运算符(例如 *)不能对小于 int 的整数类型进行操作。在应用运算符之前,这些类型的表达式被提升为int。参见 6.3.1.4 第 2 段和多次出现的“整数提升”一词。但这与编译器生成的汇编指令有些正交,它们在ints 上运行,因为即使允许编译器计算更短的结果(因为结果立即存储在例如,短类型)。

    关于int64 f = d * e;,其中de 的类型为int,根据相同的提升规则,乘法作为int 完成。从技术上讲,溢出是未定义的行为,您在这里得到的是二进制补码结果,但您可以根据标准得到任何东西。

    注意:提升规则在提升时区分有符号和无符号类型。规则是将较小的类型提升为int,除非int 不能代表该类型的所有值,在这种情况下使用unsigned int

    【讨论】:

      【解决方案2】:

      问题是乘法是int32 * int32,它是作为int32完成的,然后将结果分配给一个int64。你会得到与double d = 3 / 2; 大致相同的效果,它会使用整数除法将 3 除以 2,并将 1.0 分配给d

      无论何时,您都必须注意表达式或子表达式的类型。这需要确保将适当的操作计算为适当的类型,例如将被乘数之一转换为 int64,或者(在我的示例中)3.0 / 2(float)3 / 2

      【讨论】:

      • 说得很好。 @azraiyl 应该将该行更改为 int64 f = (int64)d * e;
      • 对不起,我没有说我知道这里的解决方案。我感兴趣的是为什么在第一种情况下乘法是 int32 * int32 而不是 int8 * int8。即使 CPU 仅支持 int32 乘法,它也可以在乘法后转换回 int8。但 IA32 imul 指令适用于 8 位寄存器(AL,...)。
      • @azrayl:至少在 C90 中,C 将所有算术操作数提升为 int,如果它们是较小的类型的话。看一眼 C99 标准就表明情况不再如此,但我不太确定。您使用的是什么 C 编译器,如果适用,使用哪些选项?
      【解决方案3】:

      阅读 K&R(原版)。所有整数运算都使用自然整数类型完成,除非它涉及(或强制转换)更大的变量。 char 上的操作被转换为 32 位,因为这是该架构上整数的自然大小。两个 32 位整数的乘法是在 32 位中完成的,因为没有任何东西将其转换为更大的值(直到您将其分配给 64 位变量,但为时已晚)。如果您希望操作以 64 位进行,请将一个或两个 int 转换为 64 位。

      int64 f = (int64)d * e;
      

      【讨论】:

        【解决方案4】:

        a * b被计算为int,然后转换为接收变量类型(恰好是int)

        d * e被计算为int,然后转换为接收变量类型(恰好是int64)

        如果任一类型变量大于 int(或为浮点),则将使用该类型。但由于乘法中使用的所有类型都是 int 或更小,因此使用了 int。

        【讨论】:

          猜你喜欢
          • 2016-07-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-08-17
          • 1970-01-01
          • 1970-01-01
          • 2017-02-08
          相关资源
          最近更新 更多