文章目录
- 移位操作符(只针对整数)
- <<左移操作符
- >>右移操作符
- 位操作符
- &:按位与
- |:按位或
- ^:按位异或
- ~:按位取反
- 一些结论
- 逗号表达式
- 操作符的属性
- 优先级
- 结合性
- 表达式求值
- 整型提升
- 算术转换
- 一些习题
- 数值交换
- 求一个数二进制表达式中1的个数
- 求单身狗
- 1变0,0变1
由于数据在电脑中都是以补码的形式存储的,所以以下操作符都是对补码进行操作
移位操作符(只针对整数)
<<左移操作符
左移操作符可以让整个数往左移若干位
如5<<2,得到的结果是20

前面被移出的位丢弃,后面往后加0
>>右移操作符
右移操作符分为两类,逻辑右移和算数右移,不同的编译器实现的功能不同
- 逻辑右移:和左移类似,直接往右移动若干位,右边多出来的空位补0(这样也就容易出现负数右移之后变成正数的情况)
- 算术右移:往右移动若干位,左边空出来的位置补符号数
如图,5>>2,结果是1

-1>>2,前面两个补1,结果还是-1

注意:不要移动负数位,没有这种规则
位操作符
&:按位与
逐步比较两个数的每一位,如果有0则结果为0,如果两个都是1则结果为1

|:按位或
逐步比较两个数的每一位,如果有1则结果为1,如果两个都是0则结果为0

^:按位异或
逐步比较两个数的每一位,如果相同则结果为0,如果不同则结果为1

~:按位取反
把传入数的每一位都颠倒过来

一些结论
- a^0=a
- a^a=0
- a&1=末位数字
- a&(a-1)=去掉最后面的1得到的数
逗号表达式

此时c被赋上了b的值,同时前面的a++也执行过了
说明逗号表达式中是以最后一个式子为准,但是前面的表达式依然会执行
逗号表达式可以让循环变得更加简洁
#include<stdio.h>
int main()
{
int a = 0;
scanf("%d", &a);
if(test(a), a++, a > 0)
{
printf("hello");
}
return 0;
}
此时在if语句中,先调用了test函数和a++,最后的语句才是真正的判断条件
不然这样写显得冗余
#include<stdio.h>
int main()
{
int a = 0;
scanf("%d", &a);
test(a);
a++;
if(a > 0)
{
printf("hello");
test(a);
a++;
}
return 0;
}
[]:下标访问操作符
操作数是数组名和索引值
():函数调用操作符
操作数是函数名和传入的参数
操作符的属性
优先级
和数学里乘除比加减更加优先一样,C语言中各种操作符的优先级也不一样
常用操作符优先级如下:
- 圆括号()
- 自增运算符 ++,自减运算符 –
- 单目运算符 + -(表示正负)
- 乘法 * ,除法 /
- 加法 +,减法 -
- 关系运算符 < >
- 赋值运算符 =
其中圆括号优先级较高,可以改变其他操作符的优先级
- 优先级只是相邻操作符的比较,如果不相邻,就有可能产生歧义
如a*b + c*d + e*f,第一个加号和最后一个乘号的优先级不好比较,不同的编译器可能产生不一样的运算路径
结合性
如a + b + c,编译器是从左往右算的,因为加法的结合性是从左往右

参考网站:
https://zh.cppreference.com/w/c/language/operator_precedence
表达式求值
整型提升
- C语言中的运算通常至少以缺省整形类型(int类型)的精度来进行
- 在CPU中,加法等运算的操作数长度一般是四个字节(int类型的长度)
- 而如果要将两个char类型的数进行运算,就需要进行整型提升,也就是char或者short类型的操作数在使用前被调整成int类型
两个char类型的数先是将长度变为四个字节(其中有符号数补符号数,无符号数补0)变成普通整形
运算后结果被截断留后面八位(一个字节)存储下来
算术转换
如果操作数之间各自属于不同的类型,就要转化成同一种类型再运算
如整数/浮点数,整型变成了浮点型方能计算出结果
以下层次体系为寻常算术转换,下面的类型会被转化成上面的
- long double
- double
- float
- unsigned long int
- long int
- unsigned int
- int
一些习题
数值交换
在不创建新的变量的情况下,将两个数的值交换
#include<stdio.h>
int main()
{
int a = 3;
int b = 5;
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("%d\n", a);
printf("%d\n", b);
return 0;
}
- 首先要知道按位异或是遵循交换律的,也就是a ^ b ^ c = c ^ a ^ b
- 对于第二个式子来说,就相当于是把a ^ b ^ b的值赋给b,达到了把a赋给b的效果,此时b的值为a
- 对于第三个式子来说,就相当于是把a ^ b ^ a的值赋给a,完成交换
求一个数二进制表达式中1的个数
#include<stdio.h>
int main()
{
int a = 0;
int count = 0;
scanf("%d", &a);
for(a)
{
a = a & (a - 1);
count++;
}
printf("%d\n", count);
return 0;
}
这里运用的是a & (a - 1)可以使a去掉最后一个1的性质,不断地去掉一个1
相比不断模2余1再除以2更加方便
求单身狗
int singleNumber(int nums[], int numsSize),找出那个只出现一次的元素。
比如:nums = [4,1,2,1,2]
返回:4
#include<stdio.h>
int singleNumber(int nums[], int sz)
{
int i = 0;
int m = 0;
for(i = 0; i <= sz; i++)
{
m ^= nums[i];
}
return m;
}
int main()
{
int nums = [4, 1, 2, 1, 2];
int sz = sizeof(nums) / sizeof(nums[0]);
printf("%d\n", singleNumber(nums, sz));
return 0;
}
在这里运用了a ^ a = 0,a ^ 0 = 0,以及交换律的性质,把那些出现过两遍的数全部干掉,剩下的那个就是只出现过一次的
1变0,0变1
给定一个数,如13,把它第五位改成1,再改成0
#include<stdio.h>
int main()
{
int a = 13;
a = a | (a << 4);
printf("%d\n", a);
a = a & ~(a << 4);
printf("%d\n", a);
return 0;
}
- 第一部分的原理是0000 1101按位或0001 0000,而0001 0000是1左移四位得到的
- 第二部分的原理是0001 1101按位与1110 1111,而1110 1111又是0001 0000按位取反得到的
博客介绍了C语言中的移位操作符、位操作符、逗号表达式等操作符的使用,包括左移、右移、按位与、按位或等。还阐述了操作符的优先级和结合性,以及表达式求值中的整型提升和算术转换。最后通过数值交换、求二进制中1的个数等习题加深对操作符的理解。
1088

被折叠的 条评论
为什么被折叠?



