【操作符优先级及整型提升问题】

操作符的属性

 1).优先级:在一个表达式中,相邻操作符,优先级高的先算。
 2).结合性:如果两个相邻运算符优先级相同,这个时候看结合性了,根据运算符是左结合,还是右结合来决定运算顺序.
1
1

整型提升问题

 1)整型提升
 C语言中整型算数运算总是至少以缺省整型类型的精度来进行的。
  为了获得这个精度,表达式中的字符和短整型操作数在使⽤之前被转换为普通整型,这种转换称为整型提升。

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

 这个整型提升是非常重要的,也就是说CPU中的ALU在进行整形运算的时候,必须至少是4个字节,如果少于4个字节,那么要整型提升,补充空位。这个在单片机,Dsp中非常常见!
下来了查资料来补充这个知识点!!!(这是关于硬件资源的!)

 整型提升的规则:很简单,少于4字节空间的,需要整型提升,无符号数用0补充,有符号数用符号位补充!!!

int main()
{
	//char 1个字节
	char c1 = 125;
	//01111101
	//要运算发生整型提升
	//00000000 00000000 00000000 01111101 
	char c2 = 10;
	//00001010
	//00000000 00000000 00000000 00001010

	//00000000 00000000 00000000 01111101 
	//00000000 00000000 00000000 00001010 
	//00000000 00000000 00000000 10000111
	printf("%d\n", c1 + c2);//135
	char c3 = c1 + c2;
	//c3是1个字节
	//10000111
	// 以%d的形式打印,发生整型提升
	//1111111 11111111 11111111 10000111  ->补
	//1000000 00000000 00000000 01111000  ->反
	//1000000 00000000 00000000 01111001  ->原码 (-121)
	printf("%d", c3); //-121
	return 0;
}

算数转换问题

 算数转换问题也就是说,当两个数的存储空间>=4个字节且两个数的空间大小不一样时,如果两个数相运算,则要发生算数转换,也就是空间小的要向空间大的转换!
1
 这个也很重要,虽然是小知识点,但也是一块肉!!!

问题表达式解析

a*b + c*d + e*f;
//这个表达式怎么算?
//执行过程不能确定
c + --c;
//这个怎么算?
//这个代码有问题,这儿只能确定前置--的优先级高于+的优先级,只能说明先算的是--c,那么左边c的值是什么,是--c之后的值还是之前的值?不能确定,存在歧义!
int main()
{
 int i = 10;
 i = i-- - --i * ( i = -3 ) * i++ + ++i;
 printf("i = %d\n", i);
 return 0;
}
//上面的表达式一定存在歧,这个代码在不同的编译器上运算结果不相同!看下面测试结果!

1

int fun()
{
 static int count = 1;
 return ++count;
}
int main()
{
 int answer;
 answer = fun() - fun() * fun();
 printf( "%d\n", answer);//输出多少?
 return 0;
}
//这个代码歧义是很大的!
//首先说一下,关键字static修饰局部变量,改变的是count的存储位置,到静态区了,这个静态局部变量
//就不会销毁了,还有一点就是,所谓的生命周期变长了,作用区域没变,这都是废话!!!
//此代码存在的歧义就是answer = fun() - fun() * fun();此语句调用的时候,是先调用那个fun函数
//是不确定的!只能知道是先算乘法,再算减法!!!

在这里插入图片描述

#include <stdio.h>
int main()
{
 int i = 1;
 int ret = (++i) + (++i) + (++i);
 printf("%d\n", ret);
 printf("%d\n", i);
 return 0;
}
//这个代码也是有歧义的,
//尝试在linux 环境gcc编译器,VS2013环境下都执⾏,看结果。

 VS2022测试结果
在这里插入图片描述
 gcc测试结果!!!
1
 *可以通过反汇编来看一下具体在vs下是怎么执行的!!!
1
 *这个反汇编也非常简单,首先i的地址就是ebp-8,把1放到了ebp-8所指向的单元(也就是把i存在了内存中了),接下来把i的值放到eax寄存器中,在通过add加1,放到eax中,在把eax的值放到i中,完成了一次(i++),在通过ecx和edx寄存器完成两次(i++),之后把i的值赋给eax,通过两次add计算出结果赋给ret!!!

 通过上面的汇编代码分析,在VS2022下,先是完成三次i++,在求和赋给ret!!!
*这儿强调一下,读汇编语言是一个很重要的能力,如果那个语句的执行有歧义,查看汇编是一种解决问题很好的方式!!!
完结!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值