携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第20天,点击查看活动详情
算数转换
可能学会了整型提升的小伙伴就有所疑惑了,当一个数据超过整型呢?
当这些数据是long, long long , double 等数据类型计算时该如何呢?
如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类 型,否则操作就无法进行。下面的层次体系称为
寻常算术转换。
该如何转换呢? 也是像整型提升那样,都转换成整型吗? 那必须不是 我们来看看算数转换的规律
//从下往上,层次转换
long double
double
float
unsigned long int
long int
unsigned int
int
如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算!
许多操作数类型为算数类型的双目运算符会引发转化,
并以类似的方式产生结果类型。他的目的是产生一个普通类型,
同时也是运算结果的类型。这个模式称为“寻常算数转换”。
——ANSI C手册
通俗来说:算数转换朝着精度更高,空间大小更大的类型进行转换。
//错误的转换
float f=3.1415;
int a=f; //隐式转换,精度丢失!
操作符的属性
在C语言操作符详解中,我已经介绍过了C语言中的所有操作符,还没看的伙伴可以点击查看操作符详解! 复杂表达式的求值有三个影响的因素。
- 操作符的优先级
两个相邻操作符的计算顺序取决于它们的优先级。
- 操作符的结合性
当两个操作符的优先级相同时,计算顺序就要看它们的结合性,结合性就是决定从左向右,还是从右向左计算。
- 是否控制求值顺序。
控制求值顺序就是像
||和&&一样会发生短路,当一个假时另一个表达式就停止计算,当一个为真时另一个表达式就停止计算!
两个相邻的操作符先执行哪个?取决于他们的优先级。如果两者的优先级相同,取决于他们的结合性。
操作符优先级及结合性
这是
<<C和指针>>一书中操作符优先级表!
学习C语言的同学怎么可以没读过这本书,强烈安利大家学习!有需要电子版的伙伴可以私聊bug郭
操作符的优先级从上到下,由高到低! 表达式的求值部分由优先级决定!
问题表达式
//表达式一
a*b + c*d + e*f;
这个代码可能有多种结果
我们第一步只能确定在第一个乘和第一个加,是先计算a*b,而第三个乘不能确定是否比第一个加早,所以有多种计算方式。
//1
a*b
c*d
a*b+c*d
e*f
a*b+c*d+e*f
//2
a*b
c*d
e*f
a*b+c*d
a*b+c*d+e*f
//表达式二
c + c--;
注释:同上,操作符的优先级只能决定自减
--的运算在+的运算的前面,但是我们并没有办法得知,+操作符的左操作数的获取在右操作数之前还是之后求值,所以结果是不可预测的,是有歧义的。
//表达式三,非法表达式
int main()
{
int i = 10;
i = i-- - --i * ( i = -3 ) * i++ + ++i;
printf("i = %d\n", i);
return 0;
}
上面表达式的结果在不同编译器下结果不一样。
C和指针一书中整理了不同编译器下的结果
//表达式四
int fun()
{
static int count = 1;
return ++count;
}
int main()
{
int answer;
answer = fun() - fun() * fun();
printf( "%d\n", answer);//输出多少?
return 0;
}
这个代码有没有实际的问题?
有问题!
虽然在大多数的编译器上求得结果都是相同的。
但是上述代码answer = fun() - fun() * fun(); 中我们只能通过操作符的优先级得知:先算乘法,再算减法。函数的调用先后顺序无法通过操作符的优先级确定。
这样的表达式求值问题是压根没有意义的,如果学校再出此类问题,你就将<<C和指针>>一书甩在你老师面前!
//表达式五
#include <stdio.h>
int main()
{
int i = 1;
int ret = (++i) + (++i) + (++i);
printf("%d\n", ret);
printf("%d\n", i);
return 0;
}
//尝试在linux 环境gcc编译器,VS2013环境下都执行,看结果。
linux环境gcc编译器结果
10
4
vs2013环境下结果
12
4
看看同样的代码产生了不同的结果,这是为什么?
简单看一下汇编代码,就可以分析清楚!
这我就不带大家研究了,如果有兴趣的伙伴可以研究一下!
这段代码中的第一个+ 在执行的时候,第三个++是否执行,这个是不确定的,因为依靠操作符的优先级和结合性是无法决定第一个+ 和第三个前置++ 的先后顺序。
总结:
我们写出的表达式如果不能通过操作符的属性确定唯一的计算路径,那这个表达式就是存在问题的!