目录
1.隐式类型转换
//整型提升
C的整型算术运算总是至少以缺省整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。
整型提升的意义:
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度 一般就是int的字节长度,同时也是CPU的通用寄存器的长度。因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令 中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转 换为int或unsigned int,然后才能送入CPU去执行运算。
整型是按照变量的数据类型的符号位来提升的
为啥,难道不是130吗??我们之前可能还觉得很奇怪得到这个结果,学习了整型提升后,可就不能再不会喽~
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
//char等价于signed char,有符号
char a = 3;
//3的二进制:00000000000000000000000000000011
//但是char类型只有1个字节,4个字节放入一个字节中会发生截断
//截断:00000011 --- a
char b = 127;
//b的二进制:00000000000000000000000001111111
//截断:01111111 --- b
char c = a + b;
//00000011
//01111111
//整型提升:注意有符号,最高位补符号位
//00000000000000000000000000000011 --- a
//00000000000000000000000001111111 --- b
//00000000000000000000000010000010 --- c
//截断:100000010 --- c
//此时c为负数,负数提升高位补1
printf("%d", c);
//%d --- 打印十进制
//整型提升:注意负数在内存中存的是补码
//11111111111111111111111100000010 --- 补码
//11111111111111111111111100000001 --- 反码
//10000000000000000000000011111110 --- 原码
// = - 126
return 0;
}
再来看一个例子:
//char的取值范围
这里补充一个小知识:char的取值范围是怎么来的:
其它类型的取值范围同理,这里就不赘述了。
2.算术转换
就高不就低
long double
double
float
unsigned long int
long int
unsigned int
int
算术转换要合理,否则会出现精度丢失
3.操作符的属性
操作符的优先级操作符的结合性是否控制求值顺序
//属性
优先级 | 运算符 | 功能 | 结合方向 |
1 | ( ) [ ] . -> | 小括号运算 下标运算 成员运算 指向运算 | L--->R |
2 | ! ~ ++ - - + - & * (type) sizeof | 逻辑非 按位取反 自增(1) 自减(1) 取正、取反 取地址 取内容 强制类型转换 计算占用内存长度 | R--->L |
3 | * / % | 乘 除 整数取模 | L--->R |
4 | + - | 加 减 | L--->R |
5 | << >> | 位左移 位右移 | L--->R |
6 | < <= > >= | 小于 小于等于 大于 大于等于 | L--->R |
7 | == != | 等于 不等于 | L--->R |
8 | & | 按位与 | L--->R |
9 | ^ | 按位异或 | L--->R |
10 | | | 按位或 | L--->R |
11 | && | 逻辑与 | L--->R |
12 | || | 逻辑或 | L--->R |
13 | ?: | 条件运算(三目操作符) | R--->L |
14 | = op= | 双目赋值运算 双目复合赋值运算 | R--->L |
15 | , | 逗号运算 | L--->R |
注意:后缀自增自减优先级大于前缀自增自减
//非法表达式
int main()
{
int i = 10;
i = i-- - --i * (i = -3) * i++ + ++i;
printf("%d\n", i);
return 0;
}
看到上述代码是不是头都晕了,这是什么鬼??在不同的编译器下运行的结果都不一样,有4,21,22,,30,36,42,-63,-85,-86,-95,-128……编译器都凌乱了,这样的代码就没有意义,甚至是错误的。
int fun()
{
static int count = 1;
return ++count;
}
int main()
{
int answer;
answer = fun() - fun() * fun();
printf("%d\n", answer);
return 0;
}
再来看看这个,乍一看好像没有问题,但仔细琢磨一下就会发现,三个fun函数先调用哪一个呢?我们只能通过操作符的优先级得知:先算乘法, 再算减法,但函数调用顺序不同结果就不同呀。我们不知道,编译器也不知道(不同编译器下结果不同,但同一个编译器下结果是相同的)。
所以这种让人confused的代码要尽量避免,不然既是坑自己,也是坑看自己代码的队友哦。
See you next blog ~