long long vs int multiplication

azr*_*iyl 7 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);
}
Run Code Online (Sandbox Code Playgroud)

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

1
4
8
10000
-1486618624
Run Code Online (Sandbox Code Playgroud)

第一个乘法在内部转换为int32(根据汇编程序输出).第二次乘法不是铸造的.我不确定结果是否不同,因为程序在IA32上运行,或者因为它是在C标准的某处定义的.然而,我感兴趣的是,这个确切的行为是在某处定义的(ISO/IEC 9899?),因为我想更好地理解为什么以及何时我需要手动编译(我有问题从不同的架构移植程序).

Pas*_*uoq 7

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

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

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


Dav*_*ley 5

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

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