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

时间:2017-05-18 18:53:01

标签: c integer-promotion

假设我有3个变量:longintshort

long  l; 
int   i;
short s;
long  lsum;

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

 l * i * s = i * s * l = s * i * l.

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

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

如果订单确实很重要,不一定是这个例子,那会是什么?

2 个答案:

答案 0 :(得分:4)

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

当应用算术运算符时,如果其操作数的等级小于int(例如intchar),则其每个操作数首先会提升为short。如果其中一个操作数的排名仍然较高(例如long),则提升的排名较小。

来自C standard的第6.3.1节:

  

2 如果可以使用int或unsigned int,则可以在表达式中使用以下内容:

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

  •   
  • _Bool,int,signed int或unsigned int类型的位字段。

  •   
     

如果int可以表示原始类型的所有值(限制为   通过宽度,对于位字段),该值被转换为int;   否则,它将转换为unsigned int。这些被称为   整数促销。所有其他类型的整数不变   促销。

从第6.3.1.8节开始:

  

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

     

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

     

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

     

否则,如果带有符号整数类型的操作数的类型可以   表示带有unsigned的操作数类型的所有值   整数类型,然后转换具有无符号整数类型的操作数   到带有符号整数类型的操作数的类型。

     

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

作为示例(假设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 * is的值会提升为int,然后会将两个int值相乘。此时发生溢出,取消未定义的行为。然后,结果会提升为long并乘以l,结果为long类型。

在后一种情况下,首先评估l * ii的值被提升为long,然后两个long值相乘,溢出。然后将结果乘以s,首先将其提升为long。同样,结果不会溢出。

在这种情况下,我建议将最左边的操作数转换为long,以便将所有其他操作数提升为该类型。如果您使用带括号的子表达式,您可能还需要在其中应用强制转换,具体取决于您想要的结果。

答案 1 :(得分:3)

是的,请参阅"类型转换"和"类型促销"在http://www.cplusplus.com/articles/DE18T05o/

mtcars %>% 
  mutate(
    am = factor(am, labels = c("auto", "manual")),
    vs = factor(vs, labels = c("V", "S"))
  ) %>% 
  filter(am == "auto") %>%
  # mutate to drop bar while maintaining bar formatting
  mutate(mpg = ifelse(vs == "S", mpg == 0, mpg)) %>% 
  ggplot(aes(x = am, y = mpg, fill = vs)) + 
  geom_col(position = position_dodge()) +
  scale_y_continuous(limits = c(0,35)) + 
  scale_x_discrete(drop = FALSE) 

R1 = 255 R2 = 13835056960065503487

r1反映出(a * b)首先使用类型至少与int一样长,并且结果是最长操作数类型,这是无符号的,因此结果是无符号的并且溢出。