C语言(五)——操作符

目录

算术操作符

移位操作符 

左移 

右移

位操作符

赋值操作符 

单目操作符 

关系操作符 

逻辑操作符 

条件操作符 

逗号表达式 

下标引用、函数调用和结构成员 

表达式求值


算术操作符

 算术操作符

+  -  *  /  %    // "/"两端都为整数时, 则只输出整数部分,如 7/2=3  ;“%”两端必须是整数。

移位操作符 

移位操作符

>>  <<         // 二进制操作 , 只能对整数进行操作, 移动的位数只能是正数

整数的二进制表示有:原码,补码,反码

正整数的原码,补码,反码相同。

负整数的原码,补码,反码需要计算。

eg:

7:  整型占4个字节,每个字节8个比特位,第一位是符号位

所以7 的原反补是 00000000 00000000 00000000 00000111

-7:

原码:10000000 00000000 00000000 00000111

反码:11111111 11111111 11111111 11111000    //  补码 = 原码符号位不变,其他位按位取反

补码:11111111 11111111 11111111 11111001    // 补码 = 反码 + 1

整数在内存中是以补码的形式存放的。

所以,移位是对补码进行操作。

左移 

左移:左边丢弃, 右边补0

例子: 7 左移一位 

 以下输出是 14:

左移前:【00000000 00000000 00000000 00000111】        // 补码

左移后:0【00000000 00000000 00000000 00001110】        

括号中的值变为 十进制的 14

int main() {

	int a = 7;
	// 左移操作符	移动的是二进制位	
	int b = a << 1;
	printf("%d\n", b);

	return 0;
}

例子:-7 左移一位

左移前:【11111111 11111111 11111111 11111001】  // 补码

左移后: 1【1111111 11111111 11111111 111110010】        // 补码

转为 反码 :【1111111 11111111 11111111 111110001】

转为原码:【10000000 00000000 00000000 000001110】

括号中的十进制表示 -14 

所以,左移有乘2的效果

右移

右移操作符:

算术移位:右边丢弃,左边补原符号位

逻辑移位:右边丢弃,左边补0

以 7 为例

移动前:【00000000 00000000 00000000 00000111】

算术移位:【000000000 00000000 00000000 0000011】1 

逻辑移位:【000000000 00000000 00000000 00000111】1

以 -7 为例

移动前:【11111111 11111111 11111111 11111001】  // 补码

算术移位:【111111111 11111111 11111111 1111100】1

对应原码:【10000000 000000000 00000000 00000100】 →  -4

逻辑移位:【011111111 11111111 11111111 1111100】1

对应原码:【000000000 00000000 00000000 00000100】→  4

编译器使用的是  算术右移

位操作符

位操作符

&(与)  ^(异或)  |(或)       //二进制操作

按位与

两个二进制位的补码进行按位与操作:有 0 则 0 ,全 1 则 1

 按位或

两个二进制位的补码进行按位或操作:有 1 则 1 ,全 0 则 0

按位异或

两个二进制位的补码进行按位或操作:相同为 0, 相异为 1

一个数和 0 异或得到的是原值,和 1 异或得到的是这个数取反。

a ^ a 的 结果是 0 

异或支持交换律  a^a^b = a^b^a

// &   |   ^
int main() {
	int a = 3;		//  补码:00000000 00000000 00000000 00000011
	int b = -5;		//  补码:11111111 11111111 11111111 11111011
	int c = a & b;	//按位与:00000000 00000000 00000000 00000011   →   3

	int d = a | b;	//按位或:11111111 11111111 11111111 11111011
					// 原码: 10000000 00000000 00000000 00000101	→	-5

	int e = a ^ b;	//按位异或:11111111 11111111 11111111 11111000
					// 原码:   10000000 00000000 00000000 00001000	→	-8

	// %d 以为着打印有符号整数
	printf("%d\n", c);
	printf("%d\n", d);
	printf("%d\n", e);
	return 0;
}

例子: 不创建临时变量, 交换 a 和 b 的值(应用)

答1:只适用于整型

// 不创建临时变量, 交换 a 和 b 的值
int main() {

	int a = 3;
	int b = 5;
	printf("交换前:%d %d\n", a, b);

	// 异或满足交换律
	a = a ^ b;	// a=a^b
	b = a ^ b;	// b = (a^b)^b = a(原a)
	a = a ^ b;	// a = (a^b)^((a^b)^b) = b(原b)

	printf("交换后:%d %d\n", a, b);

	return 0;
}

答2:


// 不创建临时变量, 交换 a 和 b 的值
int main() {

	int a = 3;
	int b = 5;
	printf("交换前:%d %d\n", a, b);

	// 使用该方法的前提是 a+b 不能溢出
	a = a + b;	// 此时 a 中存放的是 a,b 的和
	b = a - b;	// 此时 b 中存放的是 原来 a 的值
	a = a - b;	// 此时 a 中存放的是 原来 b 的值
	printf("交换后:%d %d\n", a, b);

	return 0;
}

赋值操作符 

赋值操作符

=    +=   -=   *=   /=   &=   ^=   |=   >>=   <<=      // “a+=b”等同于 a = a + b  

单目操作符 

单目操作符:即只对一个元素进行操作  ,如符号两边都有元素则是双目操作符

! :  逻辑反操作

-   :  取负值

+  : 取正值

&  :  取地址

sizeof() :  操作数的类型长度(以字节为单位)       

        可以计算类型sizeof(int),也可以计算变量的长度;计算变量可以省略括号 即:sizeof x

        如计算数组,则计算的是整个数组的大小,即使数组中只有一个元素,单位是字节。

~   : 对一个数的二进制按位取反

int main() {

	int a = 0;
	// 00000000 00000000 00000000 00000000		补码
	// 11111111 11111111 11111111 11111111		取反  ~a
	// 10000000 00000000 00000000 00000001		~a 的原码  →  -1
	printf("%d\n", ~a);

	return 0;
}

--   : 前置、后置--         // 前置的使用规则是先 -- , 后使用

++  : 前置、后置++        // 后置的使用规则是先使用,后 ++

*   :  间接访问操作符(解引用操作符)

(类型) :   强制类型转换

关系操作符 

关系操作符

>

>=

<

<=

!=         用于测试不相等

==        用于测试相等

逻辑操作符 

逻辑操作符

&&        逻辑与        // a && b   如果左边为0, 则&&右边的操作不会再运算

||           逻辑或        // a || b      如果左边为1, 则 || 右边的操作不会再运算

条件操作符 

条件操作符(三目操作符)

exp1?exp2 : exp3

exp1为真,则执行exp2, 为假则执行exp3

逗号表达式 

逗号表达式

exp1, exp2, exp3, ... , expn

// 逗号表达式就是由逗号隔开的一系列表达式

// 逗号表达式的特点是 :从左到右依次计算, 整个表达式的结果是最后一个表达式的结果。

下标引用、函数调用和结构成员 

下标引用、函数调用和结构成员

[]        ()        .          ->        

//  结构体对象 . 成员

//  结构体指针 -> 成员

表达式求值

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

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

隐式类型转换

        C的整型算术运算总是至少以整形类型的精度来进行的。(即如果两个char进行运算,会先强制转换为整型)

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

整型提升的意义:

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

如何进行整型提升?

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

00000000 00000000 00000000 00000001

// 无符号位整型提升,直接高位补0

算术转换

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

long double

double

float

unsigned long int

long int

unsigned int

int

        如果某个操作数的类型在上面这个列表中排名较低,那么首先要转换为另外一个操作数的类型后执行运算。

警告:算术转换要合理,要不然会有一些潜在的问题。 

操作符的属性

复杂表达式的求值有三个影响的因素。
1.操作符的优先级
2.操作符的结合性
3.是否控制求值顺序。
两个相邻的操作符先执行哪个?取决于他们的优先级。如果两者的优先级相同,取决于他们的结合性。操作符优先级

优先级顺序:

括号操作符(“()”优先级最高) > 单目操作符 > 算术操作符 > 移位操作符 > 关系操作符 > 位操作符 > 逻辑操作符 > 赋值操作符 > 逗号表达式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Billie使劲学

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值