12、表达式求值
12.1、隐藏类型转换
C语言的整形算术运算总是至少以缺省整形类型的精度来计算的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前会被转换为普通整形,这种转换被称为整形提升。这是什么意思呢?我们写一个代码来说明一下。
1. //int main() 2. //{ 3. // char c1 = 5; 4. // char c2 = 127; 5. // char c3 = c1 + c2; 6. // printf("%d\n", c3); 7. // return 0; 8. //}
结果为-124;在我们这个代码中,我们需要求c的值,但是在这里我们并不是只是将a的值和b的值相加赋给c就行。在这个代码计算的过程中,我们要先将a和b转换为整形,计算出来结果也是整形,最后将这个整形赋值给c。在计算过程中,我们一般将大小小于整形类型的类型进行提升,也就是将我们的字符类型和短整型类型提升至整形类型后再进行计算,这就是我们的整形提升。
那有些人可能就会问了,这样做的意义在哪儿呢?那我们接下来就看看整型提升的意义:
搞清楚意义后有些人就想知道到底是怎么整型提升了,-124又是怎么的出来的呢?请看下文:
看到这里有些宝子可能还是不太懂,没关系我们看一下实例计算
1. //int main() 2. //{ 3. // char c1 = 5; 4. // //00000000000000000000000000000101 //补码 5. // //00000101 - c1 (截断) 6. // char c2 = 127; 7. // //00000000000000000000000001111111 //补码 8. // //01111111 - c2 9. // char c3 = c1 + c2; 10. // //00000000000000000000000000000101 (c1提升后) 11. // //00000000000000000000000001111111 (c2提升后) 12. // //00000000000000000000000010000100 //补码 13. // //10000100 - c3(截断) 14. // //%d - 10进制的形式打印有符号的整数 15. // //11111111111111111111111110000100(提升) - 补码 16. // //11111111111111111111111110000011 -反码 17. // //10000000000000000000000001111100 --> -124 18. // printf("%d\n", c3); 19. // // 20. // return 0; 21. //}
12.2、算术转换
如果操作符的各个操作属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行。下面的层次体系为寻常算数转换
如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另一个操作数的类型后执行预算
警告:
算数转换要合理,不然会有一些潜在问题
1. 隐形转化 2. float n = 3.14; 3. int f = n;//精度缺失
12.3、操作符的属性
在C语言中,我们复杂表达式求值有3个影响因素。
1.优先级
优先级表请看博主在操作符详解(1)里的关于优先级的表;
如果在一个表达式里面我们无法确定优先级的时候,我们可以采取加括号的方式。 另外需要注意:只有相邻操作符才需要讨论操作符的优先级。
如果相邻操作符的优先级一样的话,这个时候就取决于我们的结合性。
2.结合性
关于结合性,操作符详解(1)的表也有介绍
3.是否控制求值顺序
虽然我们了解了我们复杂表达式求值有3个影响因素。但是即使是这样我们也不能确定我们表达式计算的唯一路径。
在两种方法都是可以的。在这个代码中我们只能确定乘号比加号早,但是无法确定哪个乘法比加号早。这种表达式我们称之为问题表达式。
这里有人就要问了,这里的答案不都一样的吗?那么接下来我就再写一个问题表达式。
这道题呢就是一个问题表达式,不同的编译器呢就会有不同的结果
在C语言中,我们的函数调用也会受到问题表达式的影响
1. //int fun() 2. //{ 3. // static int count = 1; 4. // return ++count; 5. //} 6. //int main() 7. //{ 8. // int answer; 9. // answer = fun() - fun() * fun(); 10. // printf("%d\n", answer); 11. // return 0; 12. //}
在这个代码中我们只能确定乘号比减号先算,但是无法确定哪个函数优先调用。因此它也会产生不同的结果,这个代码也是我们的问题代码。
所以在我们的代码中我们无法考我们操作符的优先级来确定我们表达式的唯一路径的式子都存在着一定的问题,我们写代码的过程要尽可能的避免问题表达式的书写。