文章目录
-
目录
[1.1 左移操作符 <<](#1.1 左移操作符 <<)
[1.2 右移操作符 >>](#1.2 右移操作符 >>)
[二、位操作符 :& | ^ ~](#二、位操作符 :& | ^ ~)
[2.1 按位与操作符 &](#2.1 按位与操作符 &)
[2.2 按位或操作符 |](#2.2 按位或操作符 |)
[2.3 按位异或操作符 ^](#2.3 按位异或操作符 ^)
[2.4 按位取反操作符 ~](#2.4 按位取反操作符 ~)
[四、下标引用操作符 [ ]](#四、下标引用操作符 [ ])
前言
在计算机系统中,数值⼀律⽤补码来表⽰和存储。原因在于,使⽤补码,可以将符号位和数值域统⼀ 处理;同时,加法和减法也可以统⼀处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。那么我们的移位操作符和位操作符都是对数值的二进制补码进行操作的。
一、移位操作符
注意的是:
1. 移位操作符的操作数只能是整数
2. 对于移位运算符,不要移动负数位,这个是标准未定义的。
3. 操作数为两个
1.1 左移操作符 <<
左移操作符移位规则:数值补码左边抛弃、右边补0
如下代码:
cpp
#include <stdio.h>
int main()
{
int num = 10;
int n = num << 1;
printf("n = %d\n", n); //n = 20
printf("num = %d\n", num); //num = 10
return 0;
}
它的左移操作如下图显示:

1.2 右移操作符 >>
右移操作符移位规则:⾸先右移运算分两种:
-
逻辑右移:左边⽤0填充,右边丢弃
-
算术右移:左边⽤原该值的符号位填充,右边丢弃
我们先看逻辑右移的代码:
cpp
#include <stdio.h>
int main()
{
int num = -1;
int n = num >> 1; //逻辑右移情况下:
printf("n = %d\n", n); //n = 1
printf("num = %d\n", num); //num = -1
return 0;
}
它的右移操作如下图所示:

再来看看算术右移情况下:
cpp
#include <stdio.h>
int main()
{
int num = -1;
int n = num >> 1; //算术右移情况下:
printf("n = %d\n", n); //n = -1
printf("num = %d\n", num); //num = -1
return 0;
}
它的右移操作如下图所示:

我们可以看到对于右移操作符我们有两种不同结果,这取决于编译器使用哪种,不过市面上大多数编译器 都支持并且使用算术右移 ,在计算时,我们一般默认算术右移。
二、位操作符 :& | ^ ~
注意的是:
1.位操作符的操作数必须是整数。
2.1 按位与操作符 &
操作数为两个
使用规则:两个操作数补码对应上的两个数,只有1跟1与为1,1跟0与为0
代码如下:
cpp
#include <stdio.h>
int main()
{
int num1 = -1;
int num2 = 3;
printf("%d\n", num1 & num2); //3
return 0;
}
按位与操作如下图:

2.2 按位或操作符 |
操作数为两个
使用规则:两个操作数补码对应上的两个数,1和1、0都为1,两个0才为0
代码如下:
cpp
#include <stdio.h>
int main()
{
int num1 = -1;
int num2 = 3;
printf("%d\n", num1 | num2); //-1
return 0;
}
按位或操作如下图:

2.3 按位异或操作符 ^
操作数为两个
使用规则:两个操作数补码对应上的两个数,相同为0,不同为1
代码如下:
cpp
#include <stdio.h>
int main()
{
int num1 = -1;
int num2 = 3;
printf("%d\n", num1 ^ num2); //-4
return 0;
}
按位异或操作如下图:

2.4 按位取反操作符 ~
操作数为一个
使用规则:将操作数的补码全部取反
代码如下:
cpp
#include <stdio.h>
int main()
{
int num2 = -3;
printf("%d\n", ~num2 ); //2
return 0;
}
按位取反操作如下图:

三、逗号表达式
逗号表达式,就是⽤逗号隔开的多个表达式并且可能是C语言中最被低估的操作符之一。它的形式为:
cpp
exp1, exp2, exp3, ...expN
逗号表达式,从左向右依次执⾏,整个表达式的结果是最后⼀个表达式的结果。
我们用代码练习一下吧,以便加深印象。
cpp
#include <stdio.h>
int main()
{
//代码1
int a = 1;
int b = 2;
int c = (a > b, a = b + 10, a, b = a + 1);//逗号表达式
//c等于多少呢?
printf("%d\n", c);
return 0;
}
在这逗号表达式中,我们从始至终要记住,整个表达式的结果是最后⼀个表达式的结果。
那么我们就可以知道,a>b为假=0,a=b+10为a=12,a=12,b=a+1为b=13,那么整个表达式最后一个结果就是13,所以c=13.

四、下标引用操作符 [ ]
操作数:⼀个数组名+⼀个索引值
cpp
#include <stdio.h>
int main()
{
int arr[10];//创建数组
arr[9] = 10;//实⽤下标引⽤操作符。[]的两个操作数是arr和9。
return 0;
}
需要注意的是下标引用操作符的操作数最少为1个,且只能是数组名,如下代码:
cpp
#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };//创建数组
arr[9] = 10;//实⽤下标引⽤操作符。[]的两个操作数是arr和9。
return 0;
}
五、函数调用操作符()
接受⼀个或者多个操作数:第⼀个操作数是函数名,剩余的操作数就是传递给函数的参数。
代码如下:
cpp
#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;
}
这里要注意的是:函数必须紧跟着函数调用操作符,也可以说函数必须有函数调用操作符。
像sizeof就不是函数,它是一个操作符。
cpp
#include <stdio.h>
int main()
{
int a = 10;
printf("%d\n", sizeof(a));//别看它紧跟着函数调用操作符,其实不然
printf("%d\n", sizeof a); //它可以不跟着的,也就说明了sizeof不是函数,而是一个操作符
return 0;
}