【C语言】表达式求值

目录

 

1.隐式类型转换 

//整型提升

 //char的取值范围

2.算术转换

3.操作符的属性

//属性 

//非法表达式 


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;
}

再来看一个例子: 

c 只要参与表达式运算 , 就会发生整形提升 , 表达式 +c , 就会发生提升 , 所以 sizeof(+c) 4 个字
节。 表达式 - c 也会发生整形提升 , 所以 sizeof( - c) 4 个字节, 但是 sizeof(c)  就是 1 个字节。

 //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 ~

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值