不同数据类型的乘法变量的顺序是否会导致不同的结果?

Ngu*_* al 4 c integer-promotion

假设我有 3 个变量: a long、 anint和 a short

long  l; 
int   i;
short s;
long  lsum;
Run Code Online (Sandbox Code Playgroud)

如果这是纯数学,因为乘法具有可交换性,所以这些变量的顺序无关紧要。

 l * i * s = i * s * l = s * i * l.
Run Code Online (Sandbox Code Playgroud)

lsum成为这 3 个变量相乘的容器。

在 C 中,是否会出现这些变量的特定顺序导致不同结果的情况?

如果在某种情况下顺序确实很重要,不一定来自这个例子,那会是什么?

dbu*_*ush 5

由于整数促销,订单确实很重要。

应用算术运算符时,int如果其等级小于int(例如charshort),则首先提升其每个操作数。如果这些操作数之一仍然具有更高的等级(例如long),则提升较小的等级。

来自C 标准的第 6.3.1 节:

2可以在可以使用 int 或 unsigned int 的表达式中使用以下内容:

  • 具有整数类型(int 或 unsigned int 除外)的对象或表达式,其整数转换等级小于或等于 int 和 unsigned int 的等级。

  • _Bool、int、signed int 或 unsigned int 类型的位域。

如果 int 可以表示原始类型的所有值(受宽度限制,对于位域),则将该值转换为 int;否则,它被转换为无符号整数。这些被称为整数提升。整数提升不会改变所有其他类型。

来自第 6.3.1.8 节:

如果两个操作数的类型相同,则不需要进一步转换。

否则,如果两个操作数都具有有符号整数类型或都具有无符号整数类型,则将具有较小整数转换等级的类型的操作数转换为具有较大等级的操作数的类型。

否则,如果具有无符号整数类型的操作数的秩大于或等于另一个操作数的类型的秩,则将具有有符号整数类型的操作数转换为具有无符号整数类型的操作数的类型。

否则,如果有符号整数类型操作数的类型可以表示无符号整数类型操作数类型的所有值,则将无符号整数类型操作数转换为有符号整数类型操作数的类型。

否则,两个操作数都被转换为与带符号整数类型的操作数的类型对应的无符号整数类型。

举个例子(假设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);
Run Code Online (Sandbox Code Playgroud)

输出:

s * i * l=0
l * i * s=1000000000000000
Run Code Online (Sandbox Code Playgroud)

In this example, s * i is evaluated first. The value of s is promoted to int, then the two int values are multiplied. At this point an overflow occurs unvoking undefined behavior. The result is then promoted to long and multiplied by l, with the result being of type long.

In the latter case, l * i is evaluated first. The value of i is promoted to long, then the two long values are multiplied and an overflow does not occur. The result is then multiplied by s, which is first promoted to long. Again, the result does not overflow.

In a situation like this, I'd recommend casting the leftmost operand to long so that all other operands are promoted to that type. If you have parenthesized subexpressions you may need to apply a cast there as well, depending on the result you want.