9

可能重复:
分配给较大宽度整数时的 C 整数溢出行为

我在谷歌搜索中没有找到明确的答案。假设您有两个表达式:

int16_t a16 = 100;
int16_t b16 = 2000;
int16_t result16 = (a16 * b16) / a16;

int8_t a8 = 100;
int8_t b8 = 20;
int8_t result8 = (a8* b8) / a8;

在评估表达式时(a16 * b16) / a16(a8 * b8) / a8它们是否总是int在评估期间提升到,然后在赋值之前将最终结果转换回所需的类型(int16_tint8_t),或者这个整数提升完全是可选的?是否总是在评估整数表达式时进行整数提升,还是只是允许?

如果它总是完成,那么我可以预期这两个操作不会溢出(假设int是 32 位)。如果只允许完成(而不是要求),那么操作可能会溢出。我想更好地了解这种行为。

4

3 回答 3

6
int16_t result16 = (a16 * b16) / a16;
int8_t result8 = (a8* b8) / a8;

这些声明与以下内容相同:

int16_t result16 = (int16_t) ((int) a16 * (int) b16) / (int) a16);
int8_t result8 = (int8_t) ((int) a8 * (int) b8) / (int) a8);

符合要求的实现需要整数提升。默认情况下,一些嵌入式编译器不执行整数提升以提高代码密度(例如:MPLAB C18 编译器),但这些编译器通常也具有要符合的ANSI模式。

现在对于 C,行为是用抽象机器来描述的,其中优化问题是无关紧要的。如果编译器可以在不执行整数提升的情况下为程序实现相同的可观察行为,则可以不这样做。

假设你int是 32 位的,你是对的,这个表达式:(a16 * b16) / a16不能溢出。

于 2012-10-09T20:37:53.493 回答
4

首先,我们有整数促销,6.3.1.1/2。脚注 58 说:

整数提升仅适用于:作为通常算术转换的一部分,适用于某些参数表达式,适用于一元 +、- 和 ~ 运算符的操作数,以及移位运算符的两个操作数,由它们各自的子条款指定。

其次,我们有通常的算术转换(6.3.1.8):

[T] 整数提升在两个操作数上执行。然后将以下规则应用于提升的操作数:

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

最后,我们有操作员。例如,乘法表示 (6.5.5):

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

因此,在表达式a8 * b8中,两个操作数都int被整数提升提升为,然后“不需要进一步转换”,因此表达式的结果也具有类型int

于 2012-10-09T20:46:20.543 回答
2

没有必要执行整数提升,如果没有它们的结果与使用整数提升的结果完全相同(这是 as-if 规则的一个实例,实现可以做任何它想做的事情,如果它是与标准规定的方式没有区别)。

算术运算符(6.5.5、6.5.6)的规范说整数提升是在操作数上执行的,所以你可以依赖“好像”。

但是,您不能绝对确定int16_t操作不会溢出,因为int它本身可能只有 16 位。

于 2012-10-09T20:38:02.407 回答