可能重复:
C integer overflow behaviour when assigning to larger-width integers
我在google搜索中没有找到明确的答案。假设你有两个表达式:
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_t
在分配之前,还是int8_t
),或者这个整数提升是完全可选的?在评估整数表达式时总是进行整数提升,还是只是简单地允许?
如果它总是完成,那么我可以预期这两个操作不会溢出(假设int
是32位)。如果只允许(并且不需要),则操作可能会溢出。我想更好地了解这种行为。
答案 0 :(得分: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
不能溢出。
答案 1 :(得分:4)
首先,我们有整数促销,6.3.1.1 / 2。脚注58说:
整数促销仅适用于:通常的算术转换的一部分 参数表达式,一元+, - 和〜运算符的操作数,以及两个操作数的操作数 移位运算符,由各自的子条款指定。
其次,我们通常的算术转换(6.3.1.8):
[T]对两个操作数执行整数提升。那么 以下规则适用于提升的操作数:
- 如果两个操作数具有相同的类型,则不需要进一步转换。
最后,我们有运营商。例如,乘法说(6.5.5):
通常的算术转换是在操作数上执行的。
因此,在表达式a8 * b8
中,两个操作数都被整数提升提升为int
,然后“不需要进一步转换”,因此表达式的结果具有类型{{1同样。
答案 2 :(得分:2)
没有必要执行整数提升,如果没有它们的结果与整数提升完全相同(这是as-if规则的实例,实现可能会做任何它想要的事情,如果它与标准规定的方式无法区分)。
算术运算符(6.5.5,6.5.6)的规范表明整数提升是在操作数上执行的,因此你可以依赖“就好”。
但是,您不能绝对确定int16_t
操作不会溢出,因为int
本身可能只有16位。