一次带你理清 ‘ || ’ 和 ‘ && ’ 和 ‘ ^ ’ 等常用操作符以及其余基本操作符(上)

简介: 一次带你理清 ‘ || ’ 和 ‘ && ’ 和 ‘ ^ ’ 等常用操作符以及其余基本操作符(上)

1.操作符分类



1.算数操作符


+      -       *        /       %


  1. 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
  2. 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法
  3. % 操作符的两个操作数必须为整数。返回的是整除之后的余数


例如:

int a=5;
int b=4;
int c=5/3   --结果为1  除法结果为取商
//   int c=5/3.0  --   此时,由于除号两边有一边为浮点数,那么结果就为浮点
                    // 型-- 1.25
int d=a%b;   -- 商 1  余1  因此 d= 1
//  取模的结果是余数,且取模符号 %两边都只能是整形
注意:  d的结果一定是再 0<=d<b 的
若 int d=a%b +1 ,则结果为1~b 之间


2.位移操作符


<<   左移操作符
 >>   右移操作符


对于位移操作符,操作对象为二进制位的补码并且只能是整数


1. << 左移操作符:左边丢弃,右边补0


例如:

int a=5;

正整数原码 反码 补码相同–再内存中存储的为补码


00000000000000000000000000000101 – a的补码

此时 a<<1 意味将a向左移动 1 位

image.png


2.右移操作符:右移操作符相比左移操作符规则上有所不同


分为两种:
1.逻辑位移:左边用0填充,右边丢弃
2.算数位移:左边用原该值的符号位(最高位)填充,右边丢弃


例如:

int a=5

a再内存中存储的是补码

00000000000000000000000000000101 --补码

a>>1

若为逻辑位移

31f0c7dfb64e4e3d8ec41ea46c78664e.png


若为算数位移:


对于正数而言,最高位符号位位0,算数位移和逻辑位移结果一致。

若为负数,int a= -5;再内存中为补码

10000000000000000000000000000101–原码

符号位(最高位不变)其他位按位取反(1为0,0为1)

111111111111111111111111111111111010–反码

反码加1为补码

111111111111111111111111111111111110–补码

若为逻辑位移

a>>1

image.png

若为算数位移:

111111111111111111111111111111111110-- -1 的补码

3bdb088146294fe59fc7d371504126f4.png

不难发现:正数的逻辑位移和算数位移是结果相同的,但是负数的逻辑位移和算数位移不一样,应当注意。


那么对于负数的右移到底是算数位移还是逻辑位移呢?


在不同的编译器上采取的处理方式不一样,为其中的一种,但多数都是算数位移


3.位操作符


&   //按位与
     |   //按位或
     ^   //按位异或


注意:它们之间操作的都是整数且操作的是二进制位的补码


1. 按位与(&)


运算规则:两个整数对应的二进制位同时为1,结果才为1,否则为0。


int a=5;

int b=1;

int c=a&b; c的结果是多少呢?


a再内存中存储的是二进制补码

a&b:
00000000000000000000000000000101   --  a 补码
00000000000000000000000000000001   --  b 补码


有一个0则为0,只有同为1才为1

00000000000000000000000000000001  -- c 的补码
由于正整数的原码 反码 补码相同,打印时打印的是原码的结果
因此 c 结果为5


对于含负数的按位或:

int a=5;

int b=-2;

int c=a&b;

00000000000000000000000000000101  -- a 补码
10000000000000000000000000000010  -- b 原码
11111111111111111111111111111101  -- b 反码
11111111111111111111111111111110  -- b 补码  


a&b:

00000000000000000000000000000101  -- a 补码
11111111111111111111111111111110  -- b 补码


有一个0则为0,只有同为1才为1

00000000000000000000000000000100  -- c 的补码
由于打印时打印的是原码,因此 c 结果为 4


在这你有没有发现 一个正整数& 1 结果为它本身?


那么 我们就可以通过前面的位移操作符和 按位与结合,获取一个整数二进制中的每一位数

例如:获取 5 二进制中的每一位数

for(int i;i<32;i++);
{
int c=(5>>i)&1;
}


2.按位或( | )


运算规则:两个整数对应的二进制位有一个1则为1,只有同为0才为0

int a=5;

int b=2;

int c=a&b; c的结果是多少呢?


 a | b:
00000000000000000000000000000101   --  a 补码
00000000000000000000000000000010   --  b 补码


有一个1则为1,只有同为0才为0

00000000000000000000000000000111  -- c 补码


打印时,打印的是原码,因此 c 的 结果为 7

对于含负数的按位或:

int a=5;

int b=-2;

int c=a|b;

00000000000000000000000000000101  -- a 补码
10000000000000000000000000000010  -- b 原码
11111111111111111111111111111101  -- b 反码
11111111111111111111111111111110  -- b 补码


a|b:

00000000000000000000000000000101  -- a 补码
11111111111111111111111111111110  -- b 补码


有一个1则为1,只有同为0才为0

11111111111111111111111111111111  -- c 补码


打印时,打印的是原码,因此负数的补码还需要还原为原码

11111111111111111111111111111111  -- c 补码
补码-1 得到反码
11111111111111111111111111111110  -- c 反码
反码符号位不变,其余按位取反
10000000000000000000000000000001  -- c 原码
所以 c 的结果为 -1


3.按位异或(^)


运算规则:两个整数对应的二进制位相同,则结果为0,否则为1

int a=5;

int b=3;

int c=a^b;

000000000000000000000000000000101  -- a 补码
000000000000000000000000000000011  -- b 补码


a^b:

000000000000000000000000000000101  -- a 补码
000000000000000000000000000000011  -- b 补码


相同为0,相异为1

00000000000000000000000000000110  -- c 原码
打印c 的结果为 6


对于含负数的按位与:

int a=5;

int b= -3;

int c=a^b;

000000000000000000000000000000101  -- a 补码
100000000000000000000000000000011  -- b 原码
111111111111111111111111111111100  -- b 反码
111111111111111111111111111111101  -- b 补码


a^b:

000000000000000000000000000000101  -- a 补码
111111111111111111111111111111101  -- b 补码


相同为0,相异为1

111111111111111111111111111111000  -- c 补码
打印出 c 的结果为 -8


对于按位异或,我们可以从下面的代码发现如下规律:

0^0 = 0;
1^0 = 1; //0异或一个数 = 这个数
0^1 = 1; //异或具有交换律
1^1 = 0;//自己异或自己 = 把自己置为0


再看一道经典例题:

实现两个值的交换,而不必使用临时变量。
    例如交换两个整数a=5,b=3的值,可通过下列语句实现:
    a = a^b;   //
    b = b^a;   //b=a^b^b = a^0 = a
    a = a^b;   //a=a^b^^a = a^a^b = 0^b = b


利用我们上面的规则,很容易就将两个数交换值,并且这样不会存在溢出的问题

其次,还可以利用按位与快速判断两个整数是否相等

int a=5;
int b=4;
if(a^b==0) //根据我们上述发现的规律可以知道
            //如果a b相等,那么 a^b一定为0
 a=1;
 else
 a=2;


4.复合操作符


+=     -=     *=    /=    %=    >>=    < <=     &=     |=     ^=


对于上述操作符,都是由两个操作符复合组成的,那应该如何理解呢?

例如: +=,就是加上一个数后 = 什么

int a=2;

a+=2 // a先加再赋值,最后a变成了4;

同理 a-=2;//此时a先减,最后再赋值变成里 0

后面的 *= /= >>= … 均是如此。


相关文章
|
1月前
a+=b 和 a=a+b 真的完全等价吗?
a+=b 和 a=a+b 真的完全等价吗?
24 0
|
6月前
|
机器学习/深度学习 算法 JavaScript
< 在 Js 中如何理解 ‘ 时间复杂度 ’ 和 ‘ 空间复杂度 ’ >
本文介绍了前端开发中的重要概念——时间复杂度和空间复杂度,用于评估算法效率。时间复杂度表示算法执行时间与输入数据之间的关系,空间复杂度则表示算法运行所需内存。通过对常见算法的时间、空间复杂度分析,例如线性、平方和对数阶,强调了它们在优化代码性能中的作用。文章通过案例展示了如何计算和理解这两种复杂度,并提供了优化示例,强调合理优化能显著提升代码性能。
< 在 Js 中如何理解 ‘ 时间复杂度 ’ 和 ‘ 空间复杂度 ’ >
|
6月前
|
C语言
C语言(9)----NULL、null(或者NUL)、\0、0、‘0’几者之间的区别
C语言(9)----NULL、null(或者NUL)、\0、0、‘0’几者之间的区别
92 0
|
11月前
|
Python
python str = ‘2023/11/9 0:00:00’ 转变成‘2023-11-09’
python str = ‘2023/11/9 0:00:00’ 转变成‘2023-11-09’
49 0
|
存储 编译器
一次带你理清 ‘ || ’ 和 ‘ && ’ 和 ‘ ^ ’ 等常用操作符以及其余基本操作符(下)
一次带你理清 ‘ || ’ 和 ‘ && ’ 和 ‘ ^ ’ 等常用操作符以及其余基本操作符(下)
276 0
|
存储 编译器 C语言
【C语言】 操作符(上): -- 算数 -- 移位 -- 位操作符 -- 赋值 -- 单目 -- 关系 -- 逻辑操作符1
【C语言】 操作符(上): -- 算数 -- 移位 -- 位操作符 -- 赋值 -- 单目 -- 关系 -- 逻辑操作符1
|
C语言
【C语言】 操作符(上): -- 算数 -- 移位 -- 位操作符 -- 赋值 -- 单目 -- 关系 -- 逻辑操作符4
【C语言】 操作符(上): -- 算数 -- 移位 -- 位操作符 -- 赋值 -- 单目 -- 关系 -- 逻辑操作符4
|
C++
‘this’不能用于常量表达式错误(C++)【问题解决】
‘this’不能用于常量表达式错误(C++)【问题解决】
277 0
‘this’不能用于常量表达式错误(C++)【问题解决】
|
人工智能 BI
CF1398C. Good Subarrays(思维 前缀和)
CF1398C. Good Subarrays(思维 前缀和)
103 0
|
C++
201312-5 I’m stuck!
201312-5 I’m stuck!
81 0
201312-5 I’m stuck!