目录:
1.操作符的分类
2.二进制和进制转换
3.原码、反码、补码
4.移位操作符
5.位操作符
6.单目操作符
7.逗号表达式
8.下标访问[]、函数调用()
9.结构成员访问操作符
10.操作符的属性:优先级,结合性
11.操作符优先级附录
1.操作符的分类
//sizeof是操作符不是函数,(类型)是指将数据强制转换
单目操作符 ! ++ -- & + - ~ sizeof() (数据类型)
算数操作符 + - * / %
赋值操作符 = += -= *= /= %= <<= >>= &= |= ^=
条件运算符 (bool)? (表达式1):(表达式2)
关系操作符 > >= < <= == !=
逻辑运算符 && || !
移位操作符 << >>
位操作符 & | ^
下标引用 []
函数调用 ()
结构成员访问 . ->
逗号表达式 ,
上面一些基本的像算数操作符、赋值操作符、逻辑运算符、条件运算符、关系运算符、部分单目运算符我们在前面都提到过,今天我们继续介绍一部分。操作符中有一些操作符和二进制有关系,我们先铺垫一下二进制以及进制转换的知识。
2.二进制和进制转换
其实我们经常能听到 2进制、8进制、10进制、16进制 这样的讲法,那是什么意思呢?
其实2进制、8进制、10进制、16进制是数值的不同表⽰形式⽽已。
⽐如:数值15的各种进制的表⽰形式:
1 15的2进制:11112 15的8进制:173 15的10进制:154 15的16进制:F56 //16 进制的数值之前写: 0x7 //8 进制的数值之前写: 0
2.1 进位计数制
基本概念:
数制:是人们对数量计数的一种统计规律。其计数方法是把数划分为不同的数位,当某一位累计一定数量之后,向高位进位,该位又从零开始。进位计数制可以用少量的数码表示较大的数。因而广泛采用。在这种计数制中,同一个数码在不同的数位上所表示的数值不同。
基本要素:进位基数和数位的位权
基数:计数制中使用的数码个数称为该位进位计数制的进位基数,记作R。一般而言R进位制的基数为R,就有R个数码。
位权:不同数位上的固定常数,称为该数位的位权值,简称:“位权”。用Ri 表示,R为进位基数, i 是各数位的序号。按如下方法确定。
整数部分:以小数点为起点,自右向左依次为 0,1,2,.… n-2,n-1.
小数部分:以小数点自左向右为 -1,-2,-3,…,-m
R 进制的数表示为:
十进制是人们最熟悉的数制,但机器实现十分困难!目前数字系统均是采用二进制,是机器唯一认识的数码。但书写太长易出错,为此引入八进制与十六进制的概念
2.2 过渡进制
八进制
“逢八进一”。具有0,1,2,3,4,5,6,7,八个代码。由于23=8,所以三位二制数可用一位八进制数表示。其长度压缩至二进制长度的1/3,八进制与二进制关系如表1 所示。
十六进制
“逢十六进一”。具有0 ~9;A~F十六个代码。由 于2 4=16,所以四位二进制 数可用一位十六进制数表示, 其长度压缩至二进制长度的 1/4,十六进制与二进制关系 如表2 所示
/*
例一:
(10101.11)B =1×2^4+1×2^2+1×2^0+1×2^-1+1×2^-2
=16+4+1+0.5+0.25
=(21.75)D
例二:
(165.2)o =1×8^2+6×8^1+5×8^0+2×8^-1
=64+48+5+0.25
=(117.25)D
例三:
(2A.8)H =2×16^1+10×16^0+8×16^-1
=32+10+0.5
=(42.5)D
*/
2.3 二进制转十进制
二进制最先由德国德国自然科学家、数学家、唯心主义哲学家莱布尼茨所发明
最早蕴含着二进制规律的思想出现在《周易系辞下转》的八卦图中
八卦中的每一个卦,由称为“爻”的两种符号排列而成。“――”叫做“阴爻”,相当于二进制里的0,“—”叫做“阳爻”,相当于二进制中的1,则八个方位上的八卦符号与三位二进制编码有唯一的对应关系
那我们就重点介绍⼀下⼆进制:
⾸先我们还是得从10进制讲起,其实10进制是我们⽣活中经常使⽤的,我们已经形成了很多尝试:
• 10进制中满10进1
• 10进制的数字每⼀位都是0~9的数字组成
其实⼆进制也是⼀样的
• 2进制中满2进1
• 2进制的数字每⼀位都是0~1的数字组成
那么 1101 就是⼆进制的数字了。
我们通常借助BCD编码的思想来进行十进制和二进制互换。例如25=16+8+1,则25对应的二进制码为11001.
3.原码、反码、补码
3.1原码
Tips: 原码其实就是十进制对应的二进制数
3.2反码
Tips:负数快速求反码:将真值的数值位按位取反!最高位为符号位,不变。正数没有补码,或说补码是原码本身
3.3补码
补的概念:时钟的顺逆时针转动。6-3=3;6+9-12=3;(-12是因为时钟以12为模)。由此可见-3可用+9代替,减法就变成了加法。此时称+9是-3以12为模的补数。记作 -3 三 +9 (mod 12)
结论:一个负数加上“模”即得该负数的补数。一个负数和它的补数绝对值之和即为模数。正数的补数即是本身
Tips:补码其实就是反码末位+1,由于正数没有补码,在这里我们可以得出结论:正数原反补三码一致。
3.4拓展
对于整形来说:数据存放内存中其实存放的是补码。 为什么呢?
在计算机系统中,数值⼀律⽤补码来表⽰和存储。原因在于,使⽤补码,可以将符号位和数值域统⼀ 处理;同时,加法和减法也可以统⼀处理(CPU只有加法器)此外,补码与原码相互转换,其运算 过程是相同的,不需要额外的硬件电路。
4.移位操作符
Tips:移位操作符的操作数只能是整数。
左移位符
<<移位规则:
左边抛弃,右边补0
右移位符
>>移位规则:
逻辑右移:右边抛弃,左边补0;
算数右移:左边用该值的符号位填充,右边丢弃
#include <stdio.h>
int main()
{
int num=10;
int n=num>>1;//警告:移动位数不可为负,这是未定义的即不可为int n= num >> -1
printf("n=%d\n",n);
printf("num=%d\n",num);
return 0;
}
5.位操作符
Tips:位操作符的操作数只能是整数。
& // 按位与| // 按位或^ // 按位异或~ // 按位取反
直接上代码:
#include <stdio.h>
int main()
{
int num1 = -3;
int num2 = 5;
printf("%d\n", num1 & num2);
printf("%d\n", num1 | num2);
printf("%d\n", num1 ^ num2);
printf("%d\n", ~0);
return 0;
}
一道变态的面试题:
不能创建临时变量(第三个变量),实现两个整数的交换。
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
a = a^b;
b = a^b;
a = a^b;
printf("a = %d b = %d\n", a, b);
return 0;
}
6.单目操作符
单⽬操作符有这些:!、++、--、&、*、+、-、~ 、sizeof、(类型)
单⽬操作符的特点是只有⼀个操作数,在单⽬操作符中只有 & 和 * 没有介绍,这2个操作符,我们放在 学习指针的时候学习。
7.逗号表达式
exp1, exp2, exp3, …expN
逗号表达式,就是⽤逗号隔开的多个表达式。
逗号表达式,从左向右依次执⾏。整个表达式的结果是最后⼀个表达式的结果。
//代码1
int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);//逗号表达式
c是多少?
//代码2
if (a =b + 1, c=a / 2, d > 0)
//代码3
a = get_val();
count_val(a);
while (a > 0)
{
//业务处理
//...
a = get_val();
count_val(a);
}
改写为逗号表达式
while (a = get_val(), count_val(a), a>0)
{
//业务处理
}
8.下标访问[]、函数调用()
8.1下标应用操作符[ ]
操作数:数组名+索引值(即下标)
int arr[10];
arr[9]=9;//实⽤下标引⽤操作符。
//[ ]的两个操作数是arr和9。
8.2函数调用操作符( )
接受⼀个或者多个操作数:第⼀个操作数是函数名,剩余的操作数就是传递给函数的参数。
#include <stdio.h>
void test1()
{
printf("hehe\n");
}
void test2(const char *str)
{
printf("%s\n", str);
}
int main()
{
test1(); //这⾥的()就是作为函数调⽤操作符。
test2("hello bit.");//这⾥的()就是函数调⽤操作符。
return 0;
}
9.结构成员访问操作符
讲结构体那块再说。
10.操作符的属性:
优先级
优先级指的是,如果⼀个表达式包含多个运算符,哪个运算符应该优先执⾏。各种运算符的优先级是不⼀样的。
常见优先级顺序:
• 圆括号( () )• ⾃增运算符( ++ ),⾃减运算符( -- )• 单⽬运算符( + 和 - )• 乘法( * ),除法( / )• 加法( + ),减法( - )• 关系运算符( < 、 > 等)• 赋值运算符( = )
结合性
如果两个运算符优先级相同,优先级没办法确定先计算哪个了,这时候就看结合性了,则根据运算符是左结合,还是右结合,决定执⾏顺序。⼤部分运算符是左结合(从左到右执⾏),少数运算符是右 结合(从右到左执⾏),⽐如赋值运算符(=)
即使有了操作符的优先级和结合性,我们写出的表达式依然有可能不能通过操作符的属性确定唯⼀的 计算路径,那这个表达式就是存在潜在⻛险的,建议不要写出特别复杂的表达式
操作符优先级附录
优先级 | 运算符 | 名称或含义 | 使用形式 | 结合方向 | 说明 |
1 | [] | 数组下标 | 数组名[常量表达式] | 左到右 | -- |
() | 圆括号 | (表达式)/函数名(形参表) | -- | ||
. | 成员选择(对象) | 对象.成员名 | -- | ||
-> | 成员选择(指针) | 对象指针->成员名 | -- | ||
(type){list} | 复合字面量(C99) | (type){变量列表} | -- | ||
2 | - | 负号运算符 | -表达式 | 右到左 | 单目运算符 |
~ | 按位取反运算符 | ~表达式 | |||
++ | 自增运算符 | ++变量名/变量名++ | |||
-- | 自减运算符 | --变量名/变量名-- | |||
* | 取值运算符 | *指针变量 | |||
& | 取地址运算符 | &变量名 | |||
! | 逻辑非运算符 | !表达式 | |||
(类型) | 强制类型转换 | (数据类型)表达式 | -- | ||
sizeof | 长度运算符 | sizeof(表达式) | -- | ||
_Alignof | 对齐要求(C11) | _Alignof(type) | -- | ||
3 | / | 除 | 表达式/表达式 | 左到右 | 双目运算符 |
* | 乘 | 表达式*表达式 | |||
% | 余数(取模) | 整型表达式%整型表达式 | |||
4 | + | 加 | 表达式+表达式 | 左到右 | 双目运算符 |
- | 减 | 表达式-表达式 | |||
5 | << | 左移 | 变量<<表达式 | 左到右 | 双目运算符 |
>> | 右移 | 变量>>表达式 | |||
6 | > | 大于 | 表达式>表达式 | 左到右 | 双目运算符 |
>= | 大于等于 | 表达式>=表达式 | |||
< | 小于 | 表达式<表达式 | |||
<= | 小于等于 | 表达式<=表达式 | |||
7 | == | 等于 | 表达式==表达式 | 左到右 | 双目运算符 |
!= | 不等于 | 表达式!= 表达式 | |||
8 | & | 按位与 | 表达式&表达式 | 左到右 | 双目运算符 |
9 | ^ | 按位异或 | 表达式^表达式 | 左到右 | 双目运算符 |
10 | | | 按位或 | 表达式|表达式 | 左到右 | 双目运算符 |
11 | && | 逻辑与 | 表达式&&表达式 | 左到右 | 双目运算符 |
12 | || | 逻辑或 | 表达式||表达式 | 左到右 | 双目运算符 |
13 | ?: | 表达式1? 表达式2: 表达式3 | 右到左 | 三目运算符 | |
14 | = | 赋值运算符 | 变量=表达式 | 右到左 | -- |
/= | 除后赋值 | 变量/=表达式 | -- | ||
*= | 乘后赋值 | 变量*=表达式 | -- | ||
%= | 取模后赋值 | 变量%=表达式 | -- | ||
+= | 加后赋值 | 变量+=表达式 | -- | ||
-= | 减后赋值 | 变量-=表达式 | -- | ||
<<= | 左移后赋值 | 变量<<=表达式 | -- | ||
>>= | 右移后赋值 | 变量>>=表达式 | -- | ||
&= | 按位与后赋值 | 变量&=表达式 | -- | ||
^= | 按位异或后赋值 | 变量^=表达式 | -- | ||
|= | 按位或后赋值 | 变量|=表达式 | -- | ||
15 | , | 表达式,表达式,… | 左到右 | -- |
感谢观看!