long long 与 int 乘法
给出以下代码片段:
#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?),因为我想更好地理解为什么以及何时必须手动转换(我在从不同架构移植程序时遇到问题)。
Given the following snippet:
#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);
}
The output with MinGW GCC 3.4.5 is (-O0):
1
4
8
10000
-1486618624
The first multiplication is casted to an int32 internally (according to the assembler output). The second multiplication is not casted. I'm not sure if the results differ because the program was running on a IA32, or because it is defined somewhere in the C standard. Nevertheless I'm interested if this exact behavior is defined somewhere (ISO/IEC 9899?), because I like to better understand why and when I've to cast manually (I've problems porting a program from a different architecture).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
a * b
计算为 int,然后转换为接收变量类型(恰好是 int)d * e
计算为 int,然后强制转换为接收变量类型(恰好是 int64),如果任一类型变量大于 int(或者是浮点数),则将使用该类型。但由于乘法中使用的所有类型都是 int 或更小,因此使用了 int。
a * b
is calculated as an int, and then cast to the receiving variable type (which just happens to be int)d * e
is calculated as an int, and then cast to the receiving variable type (which just happens to be int64)If either of the type variables were larger that an int (or were floating point), than that type would have been used. But since all the types used in the multiplies were int or smaller, ints were used.
阅读 K&R(原著)。所有整数运算都是使用自然整数类型完成的,除非它涉及到(或被转换)为更大的变量。对 char 的操作被转换为 32 位,因为这是该体系结构上整数的自然大小。两个 32 位整数的乘法是在 32 位中完成的,因为没有任何东西可以将其转换为更大的值(直到将其分配给 64 位变量,但为时已晚)。如果您希望该操作以 64 位进行,请将一个或两个 int 转换为 64 位。
Read K&R (the original). All integer operations are done with the natural integer type unless it involves variables that are (or are casted) to something bigger. The operations on char are casted to 32 bits because that's the natural size of integer on that architecture. The multiplication of the two 32 bit integers is done in 32 bits because nothing is casting it to anything bigger (until you assign it to the 64 bit variable, but that's too late). If you want the operation to happen in 64 bits, cast one or both ints to 64 bits.
问题是乘法是 int32 * int32,它是作为 int32 完成的,然后结果分配给 int64。使用
double d = 3 / 2;
会得到大致相同的效果,它会使用整数除法将 3 除以 2,并将 1.0 分配给d
。无论何时,您都必须注意表达式或子表达式的类型。这需要确保将适当的运算计算为适当的类型,例如将被乘数之一转换为 int64,或(在我的示例中)
3.0 / 2
或(float)3 / 2
。The problem is that the multiplication is int32 * int32, which is done as int32, and the result then assigned to an int64. You'd get much the same effect with
double d = 3 / 2;
, which would divide 3 by 2 using integer division, and assign 1.0 tod
.You have to pay attention to the type of an expression or subexpression whenever it may matter. This requires making sure the appropriate operation is calculated as the appropriate type, such as casting one of the multiplicands to int64, or (in my example)
3.0 / 2
or(float)3 / 2
.C99 标准确实指定二元运算符(例如
*
)不能对小于int
的整数类型进行操作。在应用运算符之前,这些类型的表达式将提升为int
。参见 6.3.1.4 第 2 段以及多次出现的“整数提升”一词。但这与编译器生成的汇编指令有些正交,编译器对 int 进行操作,因为即使允许编译器计算较短的结果,这也会更快(因为结果立即存储在例如,短类型的左值)。对于
int64 f = d * e;
,其中d
和e
的类型为int
,乘法如下所示符合相同提升规则的int
。从技术上讲,溢出是未定义的行为,您在这里得到的是两个补码结果,但根据标准您可以获得任何结果。注意:提升规则在提升时区分有符号和无符号类型。规则是将较小的类型提升为
int
,除非int
无法表示该类型的所有值,在这种情况下使用unsigned int
。The C99 standard does specify that binary operators such as
*
do not operate on integer types smaller thanint
. Expressions of these types are promoted toint
before the operator is applied. See 6.3.1.4 paragraph 2 and the numerous occurrences of the words "integer promotion". But this is somewhat orthogonal to the assembly instructions generated by the compiler, which operate onint
s because this is faster even when the compiler would be allowed to computed a shorter result (because the result is immediately stored in an l-value of a short type, for instance).Regarding
int64 f = d * e;
whered
ande
are of typeint
, the multiplication is done as anint
in accordance with the same promotion rules. The overflow is technically undefined behavior, you are getting two-s-complement result here, but you could get anything according to the standard.Note: the promotion rules distinguish signed and unsigned types when promoting. The rule is to promote smaller types to
int
unlessint
cannot represent all values of the type, in which caseunsigned int
is used.