表达式求值

目录

1)隐式类型转换

例子1:

例子2:

例子3:

2)算术转换

3)操作符的属性 

一些问题表达式

表达式求值的顺序一部分是由操作符的优先级和结合性决定。

同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型

1)隐式类型转换

C的整型算术运算总是至少以缺省整型类型的精度来进行的。(缺省:默认的意思)

为了获得这个精度,表达式中的字符和短整型操作数使用之前被转换为普通整型,这种转换称为整型提升

整型提升的意义:

表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。 因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。 通用CPU(general-purpose CPU)是难以直接实现两个8比特字节(两个char型)直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。

如何进行整体提升呢?

整形提升是按照变量的数据类型的符号位来提升的

#include<stdio.h>
int main()
{
	char a = -1;//-1是整数,32个比特位
	//10000000 00000000 00000000 00000001 - -1原码
	//11111111 11111111 11111111 11111110 - -1反码
	//11111111 11111111 11111111 11111111 - -1补码
	//char c只有8个比特位,放不下这么多
	//所以c里面只能放下 - 11111111
	// 
	//c的类型是char c,char c是有符号char,意味着在上面的二进制里面(11111111)
	//最高位的1把它解读为符号位,符号1表示它是负数,所以进行整数提升时,是拿它的符号位进行提升的
	// 
	//11111111 - c 假设要对c的值进行整型提升
	//c的符号位是1,提升之后变成
	//11111111 11111111 11111111 11111111(补完之后提升成一个整型)

	return 0;
}
//负数的整形提升
char c1 = -1;
变量c1的二进制位(补码)中只有8个比特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为1
提升之后的结果是:
11111111111111111111111111111111

//正数的整形提升
char c2 = 1;
变量c2的二进制位(补码)中只有8个比特位:
00000001
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为0
提升之后的结果是:
00000000000000000000000000000001
//无符号整形提升,高位补0

有符号整型提升:高位补充符号位;无符号整型提升:高位补0。

例子1:

#include<stdio.h>
int main()
{
    //我们一般把字符类型归纳在整型家族里,因为字符类型存储的ASCII码值
    //ASCII码值是整数,只要是整型家族中的成员,在内存中存储的都是它的补码
    //有符号的char能表示的范围是-128~127(取值范围)
    //ASCII的取值范围是0~127
	char a = 5;
	char b = 126;
	char c = a + b;
	
	printf("c=%d\n", c);

	return 0;
}

求c的值?(c=-125)

//int - 4byte - 32bit
//char - 1byte - 8bit
#include<stdio.h>
int main()
{
	char a = 5;
	//00000000 00000000 00000000 00000101 5
	//只存8个比特位 00000101
	char b = 126;
	//00000000 00000000 00000000 01111110
	//只存8个比特位  01111110
	char c = a + b;
	//00000000 00000000 00000000 00000101 - a
	//00000000 00000000 00000000 01111110 - b
	//00000000 00000000 00000000 10000011 
	//10000011 - c

	printf("c=%d\n", c);//-125
	//当我们要打印的时候,%d意味着我们要打印一个整数
	//c是char型,所以我们要发生整型提升
	//10000011 - c
	//提升后
	//11111111 11111111 11111111 10000011(补码)
	//11111111 11111111 11111111 10000010(反码)
	//10000000 00000000 00000000 01111101(原码)

	return 0;
}

例子2:

#include<stdio.h>
int main()
{
	char a = 0xb6;
	short b = 0xb600;
	int c = 0xb6000000;
	if (a == 0xb6)
		printf("a");
	if (b == 0xb600)
		printf("b");
	if (c == 0xb6000000)
		printf("c");
	return 0;
}

求打印的结果?(c)

#include<stdio.h>
int main()
{
	char a = 0xb6;
	short b = 0xb600;
	int c = 0xb6000000;

	if (a == 0xb6)//a即使是跟0xb6比较大小,也是会发生整型提升
		          //a发生整型提升后,结果可能跟0xb6不一样
		printf("a");

	if (b == 0xb600)//b和a一样
		printf("b");

	if (c == 0xb6000000)
		printf("c");//所以程序运行结果只打印c
	return 0;
}

实例1中的a,b要进行整形提升,但是c不需要整形提升

a,b整形提升之后,变成了负数,所以表达式 a==0xb6 , b==0xb600 的结果是假,

但是c不发生整形提升,则表 达式 c==0xb6000000 的结果是真.

所以程序输出的结果是: c

如果将char型改为unsigned,则会打印出abc。

因为无符号整型提升高位补0,最后的结果跟不提升的结果一致。

#include<stdio.h>
int main()
{
	unsigned char a = 0xb6;
	unsigned short b = 0xb600;
	int c = 0xb6000000;
	if (a == 0xb6)
		printf("a");
	if (b == 0xb600)
		printf("b");
	if (c == 0xb6000000)
		printf("c");
	return 0;
}

例子3:

int main()
{
 char c = 1;
 printf("%u\n", sizeof(c));
 printf("%u\n", sizeof(+c));
 printf("%u\n", sizeof(-c));
 return 0;
}

求打印的结果?(1,4,4)

c只要参与表达式运算,就会发生整形提升.

表达式 +c ,就会发生提升,所以 sizeof(+c) 是4个字 节.

表达式 -c 也会发生整形提升,所以 sizeof(-c) 是4个字节.

但是 sizeof(c) ,就是1个字节.

#include<stdio.h>
int main()
{
	char c = 1;
	printf("%u\n", sizeof(c));//1
	printf("%u\n", sizeof(+c));//4 因为它是整型提升之后参与运算
	printf("%u\n", sizeof(-c));//4 所以打印结果是4
	return 0;
}

以上讲的是,一个表达式里面它的类型如果达不到整型大小的char,short,计算的时候就要进行整型提升,如果一个表达式的大小已经超过一个整型呢?比如float,long long。那应该如何处理?这时要用到算术转换了。

2)算术转换

以上讲的整型提升,讨论的是大小小于整型的这种类型,它要发生整型提升;如果它的大小大于或等于整型大小的整型类型,它们在使用的时候也会进行转换,这种转换称为算术转换。

3)操作符的属性 

复杂表达式的求值有三个影响的因素。

1. 操作符的优先级

2. 操作符的结合性

3. 是否控制求值顺序。

两个相邻的操作符先执行哪个?

取决于他们的优先级如果两者的优先级相同,取决于他们的结合性

逻辑与(&&)运算符,当左边为假,右边不要算;左边为真,右边要算。

逻辑或( | | )运算符,当左边为真,右边不要算;左边为假,右边要算。

条件操作符( ? : ),当表达式1为真,表达式2算,表达式1为假,表达式3算。

逗号表达式(,),会从左到右进行依次计算,真正起到判断作用的是最后的表达式。

这些操作符会影响求值的求值顺序。

一些问题表达式

注释:代码1在计算的时候,由于*比+的优先级高,只能保证,*的计算是比+早,

但是优先级并不能决定第三个*比第一个+早执行。

所以表达式的计算机顺序就可能是:

a*b

c*d

a*b + c*d

e*f

a*b + c*d + e*f

或者:

a*b

c*d

e*f

a*b + c*d

a*b + c*d + e*f

 注释:同上,操作符的优先级只能决定自减--的运算在+的运算的前面,但是我们并没有办法得知,+操作符的左操作数的获取在右操作数之前还是之后求值,所以结果是不可预测的,是有歧义的。

表达式3在不同编译器中测试结果:非法表达式程序的结果

 

这个代码有没有实际的问题?

有问题! 虽然在大多数的编译器上求得结果都是相同的。

但是上述代码 answer = fun() - fun() * fun(); 中我们只能通过操作符的优先级得知:

先算乘法, 再算减法。 函数的调用先后顺序无法通过操作符的优先级确定。

虽然编译器运算的结果为12,但12这个结果不一定是对的。在不同编译器运行的结果可能不是12。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值