我对如何在固定点环境中处理算术计算感到困惑。 请考虑以下代码行:
/* 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;
所以,我的问题是: 我可以看出为什么案例2会产生错误的结果。但 - 编译器在情况1中做了什么产生了正确的结果? - 在案例1中,算术运算不是基本相同吗?除此之外,它分为两个陈述? - 我可以期待来自不同编译器的不同行为吗?
答案 0 :(得分:5)
这是由于通常的算术转换应用于乘法的操作数然后应用于除法,这导致 short 被提升为更大的整数类型以进行计算,然后在转让时转换为短。
6.5.5
乘法运算符部分中的draft C99 standard说:
通常的算术转换是在操作数上执行的。
我们还需要注意整数常量,544
和100
将具有 int 类型,我们可以找到有关原因的详细信息问题what are default integer values?。
然后,我们可以转到6.3.1.8
常规算术转换部分,最后我们会看到以下段落:
否则,将对两个操作数执行整数提升。那么 以下规则适用于提升的操作数:
我们最终遵循以下规则:
否则,如果带有符号整数类型的操作数的类型可以 表示带有unsigned的操作数类型的所有值 整数类型,然后转换具有无符号整数类型的操作数 到带有符号整数类型的操作数的类型。
所以计算结果是 int
使用-Wcoversion
标记gcc
,但令人惊讶的是clang
不会产生警告:
warning: conversion to 'short unsigned int' from 'int' may alter its value [-Wconversion]
res = (x*544/100);
^
这导致你在第一种情况下称为正确的结果,因为所有计算都是在 int 中完成的,在第二种情况下你会丢失中间结果乘以你将它分配回res
并将值转换为适合 short 的值。
答案 1 :(得分:-3)
程序首先计算分配的右侧部分,然后指定计算出的值。
在第一个示例中,它会在分配之前计算值,以便res
可以实际存储它。
在第二个示例中,res = (x*544);
无法容纳如此大的值并且溢出。
总之,如果你传递了short的边界,在分配编译器之前不关心。