C语言:操作符、二进制和进制转换

Hello,大家好今天让我们来一起来了解一下C语言中的操作符和进制转换吧。

一. 操作符的分类

  •  算术操作符: + 、- 、* 、/ 、%
  •  移位操作符: > • 位操作符: & | ^
  •  赋值操作符: = 、+= 、 -= 、 *= 、 /= 、%= 、>= 、&= 、|= 、^=
  •  单⽬操作符: !、++、--、&、*、+、-、~ 、sizeof、(类型)
  •  关系操作符: > 、>= 、< 、<= 、 == 、 !=
  •  逻辑操作符: && 、||
  •  条件操作符: ? :
  •  逗号表达式: ,
  •  下标引用: []
  •  函数调用: ()
  • 结构成员访问: .  、->

由于操作符中有⼀些操作符和⼆进制有关系,所以我们今天也要了解二进制和机制转换。 

二. 二进制和进制转换

我们经常能听到 2进制、8进制、10进制、16进制 这样的讲法,其实在生活中我们的身边也能发现很多的进制,例如

  • 一分钟六十秒,逢六十进一,就是六十进制
  • 一年十二个月,逢十二进一,就是十二进制
  • 一年四个季度,逢四进一,就是四进制。

但其实进制只是数值的不同表示形式而已。

比如数值12的各种进制的表示形式:

  1. 12的2进制:1100
  2. 12的8进制:14
  3. 12的10进制:12
  4. 12的16进制:c

1.2进制转10进制

二进制数为1100,转换为10进制

我们可以看到如果我们想要求值,就只需要将2进制的每一位从后往前依次乘以2^0,2^1……

就能得到我们想要的值,8进制和16进制同理,一个是8的几次幂,一个是16的几次幂。

2.10进制转2进制数字

125的2进制数

只要让每个数字都余上2求出的余数在从后往前写就是他的2进制数 。

3.2进制转8进制

8进制的数字每⼀位是0~7的数字,以在2进制转8进制数的时候,从2进制序列中右边低位开始向左每3个2进制位会换算一个8进制位,剩余不够3个2进制位的直接换算。

例如:2进制的 01101011,换成8进制:0153,0开头的数字,会被当做8进制。

4. 2进制转16进制 

16进制的数字每⼀位是0~9, a~f的数字(0 1 2 3 4 5 6 7 8 9 a b c d e f)由a~f代表10~15的数字,以在2进制转16进制数的时候,从2进制序列中右边低位开始向左每4个2进制位会换算⼀个16进制位,剩余不够4个⼆进制位的直接换算。

例如:2进制的01101011,换成16进制:0x6b,16进制表示的时候前面加0x。

三.原码、反码、补码 

整数的2进制表示方法有三种,即原码、反码和补码

有符号整数的三种表示方法均有符号位数值位两部分,2进制序列中,最高位的1位是被当做符号位,剩余的都是数值位。

符号位都是用0表示“正”,用1表示“负”。

正整数的原、反、补码都相同。

负整数的三种表示方法各不相同。

原码:直接将数值按照正负数的形式翻译成二进制得到的就是原码。

反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。

补码:反码+1就得到补码。

对于整形来说:数据存放内存中其实存放的是补码。

. 移位操作符

<< 左移操作符

>> 右移操作符

注:移位操作符的操作数只能是整数。

1.左移操作符

移位规则:左边抛弃、右边补0

 本质就是将补码整体向左移超出原本框架的数抛弃,空出来的位置补0;

2.  右移操作符

移位规则:首先右移运算分两种:

1. 逻辑右移:左边用0填充,右边丢弃

2. 算术右移:左边用原该值的符号位填充,右边丢弃

五.位操作符:&、|、^、~ 

  1. &   //按位与
  2. |    //按位或
  3. ^   //按位异或
  4. ~   //按位取反 

注:他们的操作数必须是整数。 

1.&(按位与)

有0为0,全1为1。,

#include<stdio.h>
int main()
{
	int a = -2;
	int b = 5;
	int c = a & b;
	printf("%d\n", c);
}

a的原码:10000000 00000000 00000000 00000010
b的原码:00000000 00000000 00000000 00000101
a的原码:10000000 00000000 00000000 00000010
a的反码:11111111 11111111 11111111 11111101 //1和0取反
a的补码:11111111 11111111 11111111 11111110 //反码+1
b的补码:00000000 00000000 00000000 00000101
//正数的原码,反码,补码都相同

对a的补码和b的补码,进行按位比较(有0为0,全1为1),就得到了a&b。

11111111 11111111 11111111 11111110 //a的补码
00000000 00000000 00000000 00000101 //b的补码
00000000 00000000 00000000 00000100 //a&b

00000000 00000000 00000000 00000100根据转换应为4 与结果相符。

2.| (按位或)

有1为1,全0为0。

#include<stdio.h>
int main()
{
	int a = -2;
	int b = 5;
	int c = a | b;
	printf("%d\n", c);
}

a的原码:10000000 00000000 00000000 00000010
b的原码:00000000 00000000 00000000 00000101
a的原码:10000000 00000000 00000000 00000010
a的反码:11111111 11111111 11111111 11111101 //1和0取反
a的补码:11111111 11111111 11111111 11111110 //反码+1
b的补码:00000000 00000000 00000000 00000101
//正数的原码,反码,补码都相同

打印应由原码转换,由于符号位为1,为负数,原码,反码,补码,并不相同,所以要进行取反+1。 

11111111 11111111 11111111 11111110 //a的补码
00000000 00000000 00000000 00000101 //b的补码
11111111 11111111 11111111 11111111 //由于符号位为1,为负数,所以要转换为原码
10000000 00000000 00000000 00000000 //取反
10000000 00000000 00000000 00000001 //+1,变成原码

10000000 00000000 00000000 00000001根据转换应为-1,与结果相符。 

3. ^(按位异或)

相同为0,不同为1。

#include<stdio.h>
int main()
{
	int a = -2;
	int b = 5;
	int c = a ^ b;
	printf("%d\n", c);
}

a的原码:10000000 00000000 00000000 00000010
b的原码:00000000 00000000 00000000 00000101
a的原码:10000000 00000000 00000000 00000010
a的反码:11111111 11111111 11111111 11111101 //1和0取反
a的补码:11111111 11111111 11111111 11111110 //反码+1
b的补码:00000000 00000000 00000000 00000101
//正数的原码,反码,补码都相同
11111111 11111111 11111111 11111110 //a的补码
00000000 00000000 00000000 00000101 //b的补码
11111111 11111111 11111111 11111010 //由于符号位为1,为负数,所以要转换为原码
10000000 00000000 00000000 00000101 //取反
10000000 00000000 00000000 00000110 //+1,变成原码

10000000 00000000 00000000 00000110根据转换应为-5,与结果相符。 

4.~(按位取反 )

按位取反(0变1,1变0)

#include<stdio.h>
int main()
{
	int a = -2;
	printf("%d\n", ~a);
}

a的原码:10000000 00000000 00000000 00000010
a的反码:11111111 11111111 11111111 11111101 //1和0取反
a的补码:11111111 11111111 11111111 11111110 //反码+1
        00000000 00000000 00000000 00000001 //a按位取反,符号位为0,为正数,补码=原码

 00000000 00000000 00000000 00000001根据转换应为1,与结果相符。

六.逗号表达式

逗号表达式,就是用逗号隔开的多个表达式。

逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。

#include<stdio.h>
int main()
{
	int a = 1;
	int b = 2;
	int c = (a > b, a = b + 10, a, b = a + 1);
	printf("%d\n", c);
	return 0;
}

根据逗号表达式,结果应为b=a+1的结果,但前面的表达式也至关重要,第一个表达式对整体并没有影响,到第二个表达式a=b+10,他改变了a的值让a=12,这同样也影响了第三表达式,让b=13;

最后使得此13;

七.[ ] (下标引用操作符)

操作数:⼀个数组名 + ⼀个索引值(下标) 

int arr[10];//创建数组

arr[9] = 10;//使用下标引用操作符。

[ ]的两个操作数是arr和9。

八.函数调用操作符 

接受⼀个或者多个操作数:第⼀个操作数是函数名,剩余的操作数就是传递给函数的参数。

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int a = 1;
	int b = 2;
	int c = Add(a, b);//这里的()作为函数调用操作符,Add,a和b为操作数
	printf("%d\n", c);
	return 0;
}

九.结构成员访问操作符

1.结构体成员的直接访问

结构体成员的直接访问是通过点操作符(.)访问的。点操作符接受两个操作数。

#include <stdio.h>
struct Point
{
	int x;
	int y;
};
int main()
{
	struct Point p = { 1,2 };
	printf("x: %d y: %d\n", p.x, p.y);
	return 0;
}

 使用方式:结构体变量 . 成员名

2.结构体成员的间接访问

有时候我们得到的不是⼀个结构体变量,而是得到了⼀个指向结构体的指针。

#include <stdio.h>
struct Point
{
	int x;
	int y;
};
int main()
{
	struct Point p = { 1,2 };
	struct Point* prt = &p;
	prt->x = 10;
	prt->y = 20;
	printf("x: %d y: %d\n", prt->x, prt->y);
	return 0;
}

使用方式:结构体指针->成员名 

十. 操作符的属性:优先级、结合性

1.优先级

优先级指的是,如果⼀个表达式包含多个运算符,哪个运算符应该优先执⾏。各种运算符的优先级是不⼀样的。

例如

3+4*5

由于乘法的优先级高于加法,所以会先计算 4 * 5 ,而不是先计算 3 + 4 。

2.结合性 

如果两个运算符优先级相同,优先级没办法确定先计算哪个了,这时候就看结合性了,则根据运算符是左结合,还是右结合,决定执行顺序。

下⾯是部分运算符的优先级顺序(按照优先级从高到低排列)

 圆括号( () )

  •  自增运算符( ++ ),自减运算符( -- )
  •  单目运算符( + 和 - )
  •  乘法( * ),除法( / )
  •  加法( + ),减法( - )
  •  关系运算符( < 、 > 等)
  •  赋值运算符( = )

十一.表达式求值 

1.整型提升

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

如何进行整体提升呢?

1. 有符号整数提升是按照变量的数据类型的符号位来提升的

2. 无符号整数提升,高位补0 

例如

11111111

有符号,整型提升为

 11111111 11111111 11111111 11111111

无符号

 00000000 00000000 00000000 11111111

红色部分皆是整形提升所补的。

2.算术转换

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

  1. long double
  2. double
  3. float
  4. unsigned long int
  5. long int
  6. unsigned int
  7. int

好了,今天就分享到这里吧,还请大家多多关注,下一篇见。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值