不同数据类型的乘法变量的顺序是否会导致不同的结果?
Does the order of multiplication variables of different data type cause different results?
假设我有 3 个变量:long
、int
和 short
。
long l;
int i;
short s;
long lsum;
如果这是纯数学,因为乘法具有交换律属性,这些变量的顺序无关紧要。
l * i * s = i * s * l = s * i * l.
设lsum
为这3个变量相乘的容器。
在 C 中,是否存在这些变量的特定顺序导致不同结果的情况?
如果有顺序确实重要的情况,不一定来自这个例子,那会是什么?
由于整数促销,顺序确实很重要。
当应用算术运算符时,如果其操作数的秩小于 int
(例如 char
或 short
),则其每个操作数首先提升为 int
.如果这些操作数之一仍然具有更高的等级(例如 long
),则提升较小的。
来自 C standard 的第 6.3.1 节:
2 The following may be used in an expression wherever an int or unsigned int may be used:
An object or expression with an integer type (other than int or unsigned int) whose integer conversion rank is less than or equal to
the rank of int and unsigned int.
A bit-field of type _Bool, int, signed int, or unsigned int.
If an int can represent all values of the original type (as restricted
by the width, for a bit-field), the value is converted to an int;
otherwise, it is converted to an unsigned int. These are called the
integer promotions. All other types are unchanged by the integer
promotions.
来自第 6.3.1.8 节:
If both operands have the same type, then no further conversion is
needed.
Otherwise, if both operands have signed integer types or both have
unsigned integer types, the operand with the type of lesser integer
conversion rank is converted to the type of the operand with greater
rank.
Otherwise, if the operand that has unsigned integer type has rank
greater or equal to the rank of the type of the other operand, then
the operand with signed integer type is converted to the type of the
operand with unsigned integer type.
Otherwise, if the type of the operand with signed integer type can
represent all of the values of the type of the operand with unsigned
integer type, then the operand with unsigned integer type is converted
to the type of the operand with signed integer type.
Otherwise, both operands are converted to the unsigned integer type
corresponding to the type of the operand with signed integer type.
举个例子(假设sizeof(int)
是4,sizeof(long)
是8):
int i;
short s;
long l, result;
i = 0x10000000;
s = 0x10;
l = 0x10000000;
result = s * i * l;
printf("s * i * l=%lx\n", result);
result = l * i * s;
printf("l * i * s=%lx\n", result);
输出:
s * i * l=0
l * i * s=1000000000000000
在此示例中,首先评估 s * i
。 s
的值提升为int
,然后两个int
的值相乘。此时发生溢出,取消未定义的行为。然后将结果提升为 long
并乘以 l
,结果类型为 long
.
在后一种情况下,首先计算 l * i
。 i
的值被提升为 long
,然后两个 long
的值相乘, 不会 发生溢出。然后将结果乘以 s
,首先提升为 long
。同样,结果不会溢出。
在这种情况下,我建议将最左边的操作数转换为 long
,以便所有其他操作数都提升为该类型。如果您有带括号的子表达式,您可能还需要在那里应用强制转换,具体取决于您想要的结果。
是的,参见 http://www.cplusplus.com/articles/DE18T05o/ "Type conversion" 和 "Type promotion"
unsigned a = INT_MAX;
unsigned b = INT_MAX;
unsigned long c = 255;
unsigned long r1 = a * b * c;
unsigned long r2 = c * a * b;
r1=255
r2=13835056960065503487
r1 反映了(a*b)首先完成的类型至少和int一样长,结果是最长的操作数类型,是无符号的,所以结果是无符号的并且溢出。
假设我有 3 个变量:long
、int
和 short
。
long l;
int i;
short s;
long lsum;
如果这是纯数学,因为乘法具有交换律属性,这些变量的顺序无关紧要。
l * i * s = i * s * l = s * i * l.
设lsum
为这3个变量相乘的容器。
在 C 中,是否存在这些变量的特定顺序导致不同结果的情况?
如果有顺序确实重要的情况,不一定来自这个例子,那会是什么?
由于整数促销,顺序确实很重要。
当应用算术运算符时,如果其操作数的秩小于 int
(例如 char
或 short
),则其每个操作数首先提升为 int
.如果这些操作数之一仍然具有更高的等级(例如 long
),则提升较小的。
来自 C standard 的第 6.3.1 节:
2 The following may be used in an expression wherever an int or unsigned int may be used:
An object or expression with an integer type (other than int or unsigned int) whose integer conversion rank is less than or equal to the rank of int and unsigned int.
A bit-field of type _Bool, int, signed int, or unsigned int.
If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions. All other types are unchanged by the integer promotions.
来自第 6.3.1.8 节:
If both operands have the same type, then no further conversion is needed.
Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.
Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.
Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the operand with signed integer type.
Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type.
举个例子(假设sizeof(int)
是4,sizeof(long)
是8):
int i;
short s;
long l, result;
i = 0x10000000;
s = 0x10;
l = 0x10000000;
result = s * i * l;
printf("s * i * l=%lx\n", result);
result = l * i * s;
printf("l * i * s=%lx\n", result);
输出:
s * i * l=0
l * i * s=1000000000000000
在此示例中,首先评估 s * i
。 s
的值提升为int
,然后两个int
的值相乘。此时发生溢出,取消未定义的行为。然后将结果提升为 long
并乘以 l
,结果类型为 long
.
在后一种情况下,首先计算 l * i
。 i
的值被提升为 long
,然后两个 long
的值相乘, 不会 发生溢出。然后将结果乘以 s
,首先提升为 long
。同样,结果不会溢出。
在这种情况下,我建议将最左边的操作数转换为 long
,以便所有其他操作数都提升为该类型。如果您有带括号的子表达式,您可能还需要在那里应用强制转换,具体取决于您想要的结果。
是的,参见 http://www.cplusplus.com/articles/DE18T05o/ "Type conversion" 和 "Type promotion"
unsigned a = INT_MAX;
unsigned b = INT_MAX;
unsigned long c = 255;
unsigned long r1 = a * b * c;
unsigned long r2 = c * a * b;
r1=255 r2=13835056960065503487
r1 反映了(a*b)首先完成的类型至少和int一样长,结果是最长的操作数类型,是无符号的,所以结果是无符号的并且溢出。