整数溢出如何在C中起作用?

swa*_*712 2 c arithmetic-expressions overflow integer-promotion

我对如何在固定点环境中处理算术计算感到困惑.考虑以下代码行:

/* unsigned short is 16 bit.*/
unsigned short x = 1000;
unsigned short res;

/* Case1: The following yields correct result  in res */
res = (x*544/100);

/* Case2: The following yields wrong result in res*/
res = (x*544); /* expected overflow here */
res = res/100;
Run Code Online (Sandbox Code Playgroud)

所以,我的问题是:我可以看出为什么案例2会产生错误的结果.但是 - 编译器在情况1中产生正确结果的是什么? - 在案例1中,算术运算不是基本相同吗?除此之外,它分为两个陈述? - 我可以期待来自不同编译器的不同行为吗?

Sha*_*our 5

这是由于通常的算术转换应用于乘法的操作数然后应用于除法,这导致将short提升为更大的整数类型以用于计算,然后在赋值时转换为short.

草案C99标准中部分6.5.5 乘法运算符说:

通常的算术转换是在操作数上执行的.

我们还需要注意整数常量,544并且100会有int类型,我们可以在问题中找到有关为什么是默认整数值的详细信息.

然后我们可以转到6.3.1.8 常规算术转换部分,最后我们会在段落中说:

否则,将对两个操作数执行整数提升.然后将以下规则应用于提升的操作数:

我们最终遵循以下规则:

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

所以计算的结果是一个int

使用-Wcoversion标志gcc但令人惊讶的是不会clang产生警告:

warning: conversion to 'short unsigned int' from 'int' may alter its value [-Wconversion]
res = (x*544/100);
      ^
Run Code Online (Sandbox Code Playgroud)

这导致你在第一种情况下称为正确的结果,因为所有的计算都是在第二种情况下以int形式完成的,因为你将它分配回来res并且将值转换为适合的值,所以你会失去乘法的中间结果成.