long long vs int multiplication

时间:2010-08-16 18:31:02

标签: c multiplication long-long

给出以下代码段:

#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?),因为我想更好地理解为什么以及何时我需要手动编译(我有问题从不同的架构移植程序)。< / p>

4 个答案:

答案 0 :(得分:7)

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

关于int64 f = d * e; de类型为int的{​​{1}},根据相同的促销规则,乘法将作为int完成。溢出在技术上是未定义的行为,你在这里获得了二进制补码结果,但你可以根据标准得到任何东西。

注意:促销时,促销规则会区分已签名和未签名的类型。规则是将较小的类型提升为int,除非int无法代表该类型的所有值,在这种情况下使用unsigned int

答案 1 :(得分:5)

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

只要表达式或子表达式的重要性,您就必须注意它们的类型。这需要确保将适当的操作计算为适当的类型,例如将其中一个被乘数转换为int64,或者(在我的示例中)3.0 / 2(float)3 / 2

答案 2 :(得分:3)

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

int64 f = (int64)d * e;

答案 3 :(得分:2)

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

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

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