表达式求值和类型转换(c语言初阶-5)

目录

1.表达式求值

2.隐式类型转换

2.1 整型提升:按照数据类型本身的符号位进行提升。

 2.11无符号数的整型提升                

 2.12 有符号正数的整型提升        

 2.13有符号负数的整型提升

 2.2输出类型转换

2.3 赋值类型转换

2.4算数转换

补充1:类型截断

补充2.存和取(类型的意义)

        注意:

小结:类型的意义

3.强制类型转换

3.1强制类型转换的意义:


1.表达式求值

        表达式由操作符和操作数所构成,在求值时受到操作符优先级和结合性的影响。

        在复杂表达式中,两个相邻的操作符先执行哪一个,取决于它们的优先级。如果两者优先级相同,则取决于它们的结合性。

下面一张数据表为转载:Slyar Home » C语言运算符优先级 详细列表

         这些优先级和结合性其实是没必要都记住的,重点记忆如下:

        结合性:

                单目操作符都是从右到左。

        优先级:

                下标访问操作符([ ])>自增自减操作符(++、--)>解引用操作符(*)

                赋值操作符(=)>逗号运算符(,,,......)

2.隐式类型转换

        计算机中的整型运算都需要在cpu中进行运算,但cpu中的整型运算器(只有加法运算器,没有减法运算器)只能进行4字节类型操作数的计算(即只能进行4个字节的运算,而不能进行小于4个字节数据的运算),因此,当要进行操作数运算时,小于4个字节的类型(char、short...)会首先转换到4个字节,如两个char类型数据的相加,char类型是一个字节,两个char类型数据在进行运算时首先都要转化为4个字节,这个过程称之为整型提升,当发生整型提升之后,两个数据才可以在cpu中进行运算,其运算结果的二进制序列按照相应类型进行处理后得到结果(可能发生类型截断)

       运算前,b和c首先发生整型提升(提升为4个字节),然后进行加法运算,运算结果为4个字节,把该结果存储在类型为char(1个字节)的变量a中,由于空间只有一个字节大小,因此发生类型截断,结果存在a中。

2.1 整型提升:按照数据类型本身的符号位进行提升。

 2.11无符号数的整型提升                

        无符号数的整型提升:无符号,结果始终为正数,最高位补0。

#pragma warning(disable:4996)
#include<stdio.h>
int main()
{
	unsigned char a = 5, b = 3, c;
//5-0000 0101 
//整型提升(补0)-》0000 0000 0000 0000 0000 0000 0000 0101
//3-0000 0011
//整型提升(补0)-》0000 0000 0000 0000 0000 0000 0000 0011
//加法运算之后的结果0000 0000 0000 0000 0000 0000 0000 1000
//存储到unsigned char类型中,发生类型截断
//最后存储结果为0000 1000,即8
	c = a + b;
//以%d格式化输出,发生输出类型转换,char转int,进行整型提升,原数据类型为unsigned char,补0 
//0000 0000 0000 0000 0000 0000 0000 1000
//有符号int类型进行解释,符号位为0,为正数,结果为8
	printf("%d\n", c);
	return 0;
}

2.12 有符号正数的整型提升        

        有符号正数的整型提升:有符号数,整型提升时,高位补符号位,正数补0.

#pragma warning(disable:4996)
#include<stdio.h>
//有符号正数的整型提升
int main()
{
	//char类型默认为有符号位
	char a = 3, b = 5, c;
//3-0000 0011-整型提升-0000 0000 0000 0000 0000 0000 0000 0011
//5-0000 0101-整型提升-0000 0000 0000 0000 0000 0000 0000 0101
	//加法运算结果—— 0000 0000 0000 0000 0000 0000 0000 1000
	//存储到c中,发生类型截断- 0000 1000
	c = a + b;
	//以%d格式化输出,发生整型提升,有符号正数,高位补0
	//0000 0000 0000 0000 0000 0000 0000 1000-结果为8
	printf("%d\n", c);
	return 0;
}

 2.13有符号负数的整型提升

        有符号负数的整型提升:有符号数发生整型提升补符号位,负数符号位为1,即高位补1.

#pragma warning(disable:4996)
#include<stdio.h>
//有符号正数的整型提升
int main()
{
	//char类型默认为有符号位
	char a = -3, b = -5, c;
//(-3)-1000 0011-有符号数,符号位为1,转为补码
//补码-1111 1101-提升:1111 1111 1111 1111 1111 1111 1111 1101
//(-5)-1000 0101-有符号数,符号位为1,转为补码
//补码-1111 1011-提升:1111 1111 1111 1111 1111 1111 1111 1011
//加法运算结果——    11111 1111 1111 1111 1111 1111 1111 1000
	//存储到c中,发生类型截断- 1111 1000
	c = a + b;
	//以%d格式化输出,发生整型提升,有符号数,最高位为1,高位补1
	//1111 1111 1111 1111 1111 1111 1111 1000-有符号数,符号位为1
//原码1000 0000 0000 0000 0000 0000 0000 1000-结果为-8
	printf("%d\n", c);
	return 0;
}

        以上在进行printf格式化输出时候发生的整型提升是输出类型转换,下面有提到。 

 2.2输出类型转换

        当在printf中进行某种格式化输出时,其要输出的原数据类型将会在输出前转化为所要输出的类型。

2.3 赋值类型转换

         使用赋值操作符号(=)并且左右类型不同时,操作符右方数据类型会先转为操作符左方的数据类型。

2.4算数转换

        算数转换:当操作符的不同操作数属于不同类型时,是无法直接进行运算的,这时候往往需要将操作数类型转化为同一类型。而其类型转换遵循一种寻常的顺序

(低精度->高精度                 有符号->无符号                低长度->高长度),

如下:

如下:

#pragma warning(disable:4996)
#include<stdio.h>
int main()
{
	int a = -1;
	if (a < sizeof(a))
	{
		printf("hello!\n");
	}
	else
	{
		printf("hi,意外不意外!\n");
	}
	return 0;
}

 上图解析如下:

 //第一点,sizeof的返回值是4,类型是unsigned int
 //-1是int,4是unsigned int
 //第二点:'<'操作符左右操作数类型不同,因此发生算数转换,将int转为unsigned int
  //-1:1000 0000 0000 0000 0000 0000 0000 0001
  //补码:  1111 1111 1111 1111 1111 1111 1111 1111
  //将此补码以unsigned int类型进行解释读取,其值远远大于4

补充1:类型截断

        当高字节转换为低字节数据时,从低位开始存储,多余的高位丢弃。     

补充2.存和取(类型的意义)

        在int a=10;中,首先开辟出一个int类型大小的空间。将10转化成二进制序列,由于10是int型,所以存到int型变量a的空间中没有截断问题,因此直接把a的二进制序列存储到了a开辟的空间中。这里用到了10这个数据的内容,a这个变量的空间

        将10存到a中,本质与a无关,在不发生截断问题的情况下,只是把a的二进制放到了一个变量中,不管这个变量本身,就像把一定的水倒进一个水杯中,在不溢出的情况下,与水杯本身类型是无关的,其结果不过是水放到了水杯里,水还是那些水,其结果不过是把10放到了a中,10本身还是10。

        而只有在从读取变量a的内容时,其a本身才会对结果产生影响,a的类型决定了对其所存储二进制的解释。若a为有符号型,则无论其存的时候将什么类型数据放到了a的空间中,在取得时候都要以有符号型规则进行读取。

        注意:

        字面常量是有本身的数据类型的,如10,5,6等默认为int型,1.2,3.14等小数默认为double类型,‘a’,‘b’等默认为char类型

例:

#include<stdio.h>
int main()
{
	unsigned int a = -4;
	//-4本身为有符号整型int,其二进制为
	//1000 0000 0000 0000 0000 0000 0000 0100
//补码1111 1111 1111 1111 1111 1111 1111 1100
//将该二进制数存到a的空间中,与a本身无关
	//取时以a的类型对该二进制进行解释
	//a为无符号整型,则解释该二进制为无符号数,原码==补码
	//发生输出类型转换,因为a类型与输出类型相同(%u-无符号整型),不转化
	printf("%u\n", a);
	return 0;
}

小结:类型的意义

        本篇中涉及的类型的意义:

     a:  决定对开辟空间的大小

     b:决定了对二进制的解释(如何识别对应类型的二进制序列)

3.强制类型转换

        强制类型转换不会改变原类型的任何二进制排列,只改变所对应的类型,也就是对该数值的解释方法,如int a=3;unsigned b=(int)a;对数据的存储无任何影响,只有在取时类型才会起到解释作用。

        通俗来说,强制类型转换就是让你转变了对一个人的印象和看法,而对这个人本身并未产生任何影响。

        理解:一群学生在教室里上课,老师突然说一会要进来一个特别坏的人,无恶不作,学生们对这个人的印象自然是坏人,但当这个人进来之后,老师又说:“我刚刚说错了,这个人其实是一个特别好的人,舍己为人,什么好事都做。”学生们对这个人的印象就会一下子转变。但从始至终,这个人依然是这个人,其本身并没有任何变法,只是别人对他的看法在转变。

3.1强制类型转换的意义:

a:让计算机明白这是你故意做的,不用给警告。

b:让其他程序员更好的理解程序,而不是误以为是你的失误。

     

           Hello!祝大家2022年快快乐乐,平平安安,在新的一年里,希望每个人都能把不快留在昨天,从此开始新的生活,带着崭新的期望,新年快乐!

           如果有帮助的话,不如随手留下一个小小的赞,正所谓赠人玫瑰,手有余香,你们的点赞将会是我们最大的动力。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鲸落之·海

哇塞,我将因此动力加倍!冲冲冲

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值