C语言操作符进阶教程(表达式求值隐式类型转换方法)
目录
- 结构体
- 表达式求值
- 隐式类型转换
- 意义:
- 方法
- 算术转换
- 操作符属性
结构体
结构体变量的声明需要在主函数之上或者主函数中声明,如果在主函数之下则会报错,而且c语言中的结构体不能直接进行强制转换,只有结构体指针才能进行强制转换。
涉及结构体的操作符这里讲两个:.
(结构体访问操作符)->
()
首先写一段代码:
int main() { struct Stu s = {"me",19,60}; prinft("%s %d %lf",s.who,s.age,s.weight) return 0; }
这就是个结构体访问,这里的结构是:结构体变量 . 结构体成员,箭头怎么用呢?当我有一个结构体指针:
struct Stu * ps = &s; printf("%s %d %lf\n"),(*ps).name,(*ps).age,(*ps).score); return 0;
这里我是对 ps 解引用一下,找到他所指向的对象,其实和上面第一组代码的结果是一样的;但是,横看竖看都觉得有点啰嗦,我们把格局打开:
printf("%s %d %lf\n",ps->name,ps->age,ps->score); return 0;
这样是不是看着要清爽许多?->操作符的基本语法是:结构体指针 -> 结构体成员
表达式求值
我们在接触那么多的操作符后,就可以应用来进行计算,表达式求值的顺序一部分是由操作符的优先级和综合性决定。同样,有些表达式的操作数在求值过程可能需要转换成其他类型。
隐式类型转换
C语言的整型算术运算总是至少以缺省整型类型的精度来进行的。为了获取这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换被称为整型提升
意义:
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。
我们用一段代码代入一下:
int main() { char a = 5; char b = 126; char = a+b; printf("%d\n",c); return 0; }
这里的一个表达式:a+b, 其中a和b的类型都是 char 类型,按照定义来看,也就是这段代码的运行远比我们想象的复杂 ,我们知道 sizeof(char),sizeof(short)的大小肯定是小于 int 类型的,所以我们计算时就要把char,short提升成 int(unsigned int)类型,再执行运算。
方法
整型提升是按照变量的数据类型的符号位来提升的,char x = -1 中,x的二进制位(补码)只有8个比特位,char为有符号的char所以整型提升时,高位补充符号位,即为1;无符号整型提升,高位补0。
就拿刚刚的代码进行剖析:
int main() { char a = 5; //5 = 0000……0101(32位) //char类型一个字节8个比特位,就只能从5的二进制数中获取8位 //即a=00000101 //这一步叫截断 char b = 126; //126 = 0000……01111110(32位) //b = 01111110 char = a+b; //当a,b相加时整型提升 //111111111……0000011 //111111111……0000010 //100000000……1111101(符号位不变,其他位按位取反)=-125 printf("%d\n",c);// return 0;
下面这个代码就可以证明整型提升的存在:
int main() { char c= 1; printf("%u\n",sizeof(c)); printf("%u\n",sizeof(+c)); printf("%u\n",sizeof(-c)); return 0; }
从运行结果来看,为什么会是 4 呢?其实就是因为他参与了运算,进行了整型提升,变成了int类型。
算术转换
我们在刚刚谈的是 char 和 short 的计算,那如果是int 和 long ,int 和long long,int 和 float 以及 double计算呢?他们发生的就是算术转换。总的来说就是4字节以下的属于整型提升,大于4的属于算术转换。
是指如果其中操作符的各个操作数为不同类型,除非其中一个转换成另一个类型,否则无法进行操作。下面层次的系统称为寻常算术转换
char
short
int
long
long long
float
double
short a = 10; int b = 5; prinft("%d\n",sizeof(a+b+1));
printf 结果是 2 ,是因为short只有两个字节大小,在表达式中 short a 当家做主,不管放什么进来都是short,但是,sizeof 内部多表达式其实不会真实计算,我们写文件通常是 test.c,要生成 .exe 的可执行文件三步走:编译,链接,运行。在表达式进去在编译的时候就变成 2 了,根本到不了运行。
如果某个数类型在上表中排名较低,那会首先转换到另一个操作数的类型后执行运算。
PS.算术转换要合理,不然会出现潜在问题。
比如把 float 类型变成 int 类型就会造成精度丢失。
操作符属性
复杂表达式的求值有三个影响因素:
1.操作符优先级
2.操作符结合性
3.是否控制求值顺序
首先优先级是在求值时,相邻两个操作符先执行哪个的问题,当优先级相同时,取决于他们的结合性。
什么是结合性?举个栗子: a = b = c;
b的左右两侧都为 = 号,而 = 具有右结合性,故应该由右向左计算,即:a = (b = c),诸如此类,有表如下(片段):
还有一些关于优先级的常见错误值得注意一下:
有了上面这些属性是不是任意给一个表达式就可以确定一个唯一的计算路径呢?答案是:NO!比如一些问题表达式:
a*b+c*d+e*f; a + --a;
第一个可能第一感觉就是三个部分依次先乘后加给扒拉出来,这就想的太简单了,如果我把 abcdef 换成表达式,那就可能会相互影响,存在潜在问题。
第二个就不是计算顺序的问题了,是取值时机的问题,左右操作数相互关联时,计算路径可能不唯一。
诸君谨记,以上代码谁写谁特么就是猪队友,谨记!
以上就是C语言操作符进阶教程(表达式求值隐式类型转换方法)的详细内容,更多关于C语言操作符表达式求值隐式类型转换的资料请关注我们其它相关文章!