【C/C++】运算符

【C/C++】系列文章目录

第一节【C/C++】初识C语言

第二节【C/C++】变量、常量及其作用域 

第三节【C/C++】初识C语言语句、函数、数组、运算符、关键字

第四节【C/C++】初识指针、结构体

第五节【C/C++】分支、循环语句

第六节【C/C++】函数

第七节【C/C++】数组


前言

本章节是对前述章节运算符部分的补充,涉及sizeof和数组类型,移位运算符规则,整型提升,类型转换等。


一、运算符

1.左移操作符

移位规则:

左边抛弃、右边补0

 n的值不发生变化。

2.右移操作符

移位规则:
首先右移运算分两种:
1. 逻辑移位
        左边用0填充,右边丢弃
2. 算术移位
        左边用原该值的 符号位填充,右边丢弃

 我们看下vs2019中是哪种右移结果。

 对于移位运算符,不要移动负数位,这个是标准未定义的。

int num = 10;
num>>-1;//error

3.按位异或 

//不允许创建临时变量,交换两个整数的内容

int main()
{
	int a = 60;
	int b = 80;
    printf("a = %d,b= %d\n", a, b);
    //方法:1:
    a = a+b;
    b = a-b;
    a = a-b;
    printf("a = %d,b= %d\n", a, b);
	//方法2:
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;
	printf("a = %d,b= %d\n", a, b);
	return 0;
}

以上两种方法都可以将a和b的两个值交换,但是方法的1的弊端在于如果a和b的两个数很大,相加会有超出int的表示范围的可能(即溢出)。所以方法2更好一些。

a^a = 0;
x^0 = x;
  • 任何一个数按位异或它自己得到的都是0;
  • 任何一个数按位异或0得到它自己。 

4.sizeof和数组

int main()
{
	int arr[10] = { 0 };    
	char ch[10] = { 0 }; 
	printf("%d\n", sizeof(arr)); //40
	printf("%d\n", sizeof(ch));//10
	printf("%d\n", sizeof(int[10]));//40
	printf("%d\n", sizeof(char[10]));//10
	return 0;
}

我们知道sizeof可以计算变量大小,既可以使用sizeof(变量名),又可以使用sizeof(类型),计算大小。 

从上面代码可以知道,arr是变量的名称,int [10]是arr数组的类型

int main()
{
	short s = 5;
	int a = 10;
	printf("%d\n", sizeof(s = a + 2));
	printf("%d\n", s);
}

 s没有被重新计算赋值。

结论:

sizeof括号中的表达式不参与运算。 

二、表达式求值

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

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

每个表达式都有两个属性:

  1. 值属性
  2. 类型属性

1.隐式类型转换

C的整型算术运算总是至少以缺省整型类型的精度来进行的。

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

整型提升的意义

表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度

一般就是int的字节长度,同时也是CPU的通用寄存器的长度。

因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长

度。

通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令

中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转

换为int或unsigned int,然后才能送入CPU去执行运算。

如何进行整型提升呢?

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

  • 正数补0
  • 负数补1
  • 无符号数补0
int main()
{
	char a = 5;
	char b = -1;
	char c = a + b;
	return 0;
}
  1. a和b的值被提升为普通整型;
  2. 再执行加法运算​​​;
  3. 加法运算完成之后,结果将被截断,然后再存储于c中。

char类型和short类型只要参与运算就会发生整型提升,如下: 

2.算术转换

某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数的转换为另一个操作数的类型,否则操作就无法进行。下面的层次体系称为寻常算术转换

long double

double

float

unsigned long int

long int

unsigned int

int

如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算。
算术转换规则:
  1. 向精度更高的转换
  2. 向字节更长的转换
警告:
但是算术转换要合理,要不然会有一些潜在的问题。
float f = 3.14;
int num = f;//隐式转换,会有精度丢失

三、操作符属性

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

1. 操作符的优先级

2. 操作符的结合性

3. 是否控制求值顺序。

两个相邻的操作符先执行哪个?取决于他们的优先级。如果两者的优先级相同,取决于他们的结合性。

部分操作符优先级

 

总结 我们写出的表达式如果不能通过操作符的属性确定唯一的计算路径,那这个表达式就是存在问题的。

四、注意

  • 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。
  • % 操作符的两个操作数必须为整数。返回的是整除之后的余数。
  • 移位操作符的操作数只能是整数。
  • 对于移位运算符,不要移动负数位,这个是标准未定义的。
  • 全局变量定义时未初始化,默认值是0。


总结

sizeof和数组类型,操作符运算优先级,移位运算符移位规则,类型转换,整型提升。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值