C语言操作符详解(中):移位+位操作符+逗号表达式+数组与函数调用
本文是C语言操作符系列的第二篇,重点讲解了移位操作符、位操作符、逗号表达式以及数组/函数调用操作符的使用方法。主要内容包括:1)左移和右移操作符的规则及代码示例;2)按位与、或、异或和取反四种位操作符的原理与应用场景;3)逗号表达式的执行规则和简化代码的技巧;4)下标引用和函数调用操作符的基本用法。文章通过大量可直接运行的代码示例,帮助读者快速掌握这些操作符的实战应用,特别适合嵌入式开发和算法竞赛
文章目录
✨ 千呼万唤始出来!C语言操作符系列第二篇重磅更新~ 上一篇我们搞定了操作符分类、进制转换和补码这些“地基知识”,这篇直接上干货满满的实战内容!移位操作符、位操作符(嵌入式/算法竞赛的香饽饽🔥)、逗号表达式,还有天天用的数组/函数调用操作符,每个知识点都配了可直接复制运行的代码,看完就能上手实操,小白也能轻松拿捏!
一、移位操作符:<< 左移 和 >> 右移 🚀
移位操作符是专门“摆弄”整数二进制补码的工具,有两个铁律必须记住:只对整数生效,不能移负数位(比如写num >> -1,编译器会直接报错哦❌)。
1. 左移操作符 <<:左边丢,右边补0
左移的逻辑超简单,就像队列整体移动——把整数的二进制补码向左挪n位,左边超出的n位直接“扔掉”,右边空出来的位置统一补0。
-
核心规则:左移n位 = 舍弃左边n位 + 右边补n个0
-
黄金小规律:无溢出时,左移1位 ≈ 乘以2,左移n位 ≈ 乘以2ⁿ(计算效率比乘法高多啦⚡)
代码示例:左移1位实战
#include <stdio.h>
int main()
{
int a = 10; // 二进制补码:00000000 00000000 00000000 00001010
int b = a << 1; // 左移1位:右边补0 → 00000000...00010100(对应十进制20)
printf("a=%d, b=%d\n", a, b); // 输出结果:a=10, b=20
return 0;
}
左移不会修改原变量的值!示例中a始终是10,b只是接收了左移后的新结果~
2. 右移操作符 >>:算术右移是主流
右移分两种,但不用纠结——VS、GCC这些主流编译器都用算术右移,逻辑右移基本用不上。
-
算术右移规则:左边补符号位(正数补0,负数补1),右边丢n位(重点中的重点✅)
-
逻辑右移规则:左边补0,右边丢n位(仅作了解即可)
-
黄金小规律:无溢出时,右移1位 ≈ 除以2(向下取整),比如5右移1位是2,-5右移1位是-3
代码示例1:正数右移
#include <stdio.h>
int main()
{
int a = 10; // 补码:00000000...00001010(符号位为0)
int b = a >> 1; // 算术右移1位:左边补0 → 00000000...00000101(对应十进制5)
printf("a=%d, b=%d\n", a, b); // 输出结果:a=10, b=5
return 0;
}
代码示例2:负数右移(符号位是关键)
#include <stdio.h>
int main()
{
int a = -10; // 补码:11111111...11110110(符号位为1)
int b = a >> 1; // 算术右移1位:左边补1 → 11111111...11111011(对应十进制-5)
printf("a=%d, b=%d\n", a, b); // 输出结果:a=-10, b=-5
return 0;
}
二、位操作符:& | ^ ~(二进制位的魔术师🎩)
位操作符直接对二进制补码的每一位动手,操作数必须是整数。嵌入式开发配置寄存器、算法题优化性能,全靠它撑场面!四个操作符咱们逐个拆解~
1. 按位与 &:有0则0,全1才1
按位与就像“严格的门禁”——两个数的二进制位逐位对比,只要有一个位是0,结果就“放行”0;只有两个位都是1,才“放行”1。
-
核心规则:逐位运算,有0出0,全1出1
-
高频场景:
判断奇偶数:n & 1,结果1是奇数,0是偶数(超实用!) -
指定位置0:把要置0的位和0对齐,其余位和1对齐,按位与即可
代码示例:按位与运算
#include <stdio.h>
int main()
{
int a = -8; // 补码:11111111...11111000
int b = 6; // 补码:00000000...00000110
int c = a & b; // 逐位与:每一位都有0 → 00000000...00000000(对应十进制0)
printf("c=%d\n", c); // 输出结果:c=0
return 0;
}
2. 按位或 |:有1则1,全0才0
按位或和按位与相反,像“宽松的门禁”——只要有一个位是1,结果就“放行”1;只有两个位都是0,才“放行”0。
-
核心规则:逐位运算,有1出1,全0出0
-
高频场景:指定位置1(把要置1的位和1对齐,其余位和0对齐,按位或即可)
代码示例:按位或运算
#include <stdio.h>
int main()
{
int a = -8; // 补码:11111111...11111000
int b = 6; // 补码:00000000...00000110
int c = a | b; // 逐位或:每一位有1 → 11111111...11111110(对应十进制-2)
printf("c=%d\n", c); // 输出结果:c=-2
return 0;
}
3. 按位异或 ^:相同为0,相异为1
按位异或是位操作符里的“明星”,规则好记,特性超强,是很多算法题的解题关键!
-
核心规则:逐位运算,相同出0,相异出1
-
三大核心特性(必须背会🌟):
a ^ a = 0:自己和自己异或,结果必为0 -
a ^ 0 = a:和0异或,结果还是自己 -
交换律:
a ^ b = b ^ a -
高频场景:不创建临时变量交换两个整数(无溢出风险,比加减法安全)
代码示例:异或交换变量(经典面试题)
#include <stdio.h>
int main()
{
int a = 3, b = 5;
printf("交换前:a=%d, b=%d\n", a, b); // 初始:a=3, b=5
a = a ^ b; // 第一步:a = 3^5(存下两者的异或结果)
b = a ^ b; // 第二步:b = (3^5)^5 = 3(利用a^a=0,5^5=0,剩下3)
a = a ^ b; // 第三步:a = (3^5)^3 = 5(同理,3^3=0,剩下5)
printf("交换后:a=%d, b=%d\n", a, b); // 结果:a=5, b=3
return 0;
}
4. 按位取反 ~:0变1,1变0
按位取反是“反转大师”,把二进制补码的每一位(包括符号位)都反过来,0变1,1变0。
-
核心规则:逐位反转,0→1,1→0(符号位不例外)
-
关键提醒:取反结果必为负数!因为符号位会从0(正数)变1,或从1(负数)变0后,整体数值必然是负数。
代码示例:按位取反运算
#include <stdio.h>
int main()
{
int a = -1; // 补码:11111111...11111111(全1)
int b = ~a; // 取反后:00000000...00000000(对应十进制0)
printf("b=%d\n", b); // 输出结果:b=0
return 0;
}
实战练习:统计二进制中1的个数(面试必考题🔥)
用n & (n-1)的技巧,每次运算能“擦掉”n二进制中最右边的一个1,循环几次就有几个1,效率拉满!
#include <stdio.h>
int main()
{
int n = 0, count = 0;
printf("请输入一个整数:");
scanf("%d", &n);
while (n) { // n不为0就继续
n = n & (n - 1); // 擦掉最右边的1
count++; // 计数+1
}
printf("二进制中1的个数:%d\n", count);
return 0;
}
比如输入15(二进制1111),循环4次输出4;输入10(二进制1010),循环2次输出2,超精准!
三、逗号表达式:, 从左到右,取最后一个结果 📝
逗号表达式是“代码简化神器”,用逗号把多个表达式串起来,从左到右依次执行,但整个表达式的结果只看最后一个。
-
核心规则:先执行左边所有表达式,最终结果 = 最后一个表达式的值
-
高频场景:把多个操作合并成一个表达式,比如简化循环条件
代码示例:逗号表达式实战
#include <stdio.h>
int main()
{
int a = 1, b = 2;
// 逗号表达式:依次执行a>b、a=b+10、a、b=a+1,c取最后一个结果
int c = (a > b, a = b + 10, a, b = a + 1);
// 执行过程:1.判断a>b(假);2.a=12;3.取a(无用);4.b=13 → c=13
printf("c=%d\n", c); // 输出结果:c=13
// 循环条件简化:先取值、计数,再判断
int x = 0;
while (x = get_val(), count_val(x), x > 0) {
// 业务处理
}
return 0;
}
逗号表达式的括号不能省!没括号会因优先级问题出错,一定要注意~
四、下标引用 & 函数调用操作符:[] 和 () 🛠️
这两个操作符天天用,可能你没意识到它们也是“正牌操作符”~ 它们都是多操作数操作符,操作数数量不固定。
1. 下标引用操作符 []:数组访问专属
数组访问用的[]就是下标引用操作符,操作数是数组名(如arr)和下标(如i),格式为arr[i]。
-
核心规则:
arr[i] = *(arr + i)(数组名是首元素地址,arr+i是第i个元素地址,解引用就得到值) -
致命提醒:下标从0开始!
arr[10]的合法下标是0-9,越界会导致内存错误💥
代码示例:下标引用操作符
#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
printf("%d\n", arr[4]); // 操作数arr和4 → 访问第5个元素(值为5)
printf("%d\n", *(arr+4)); // 和arr[4]完全等价 → 输出5
return 0;
}
2. 函数调用操作符 ():调用函数必备
调用函数时的()就是函数调用操作符,操作数至少有1个(函数名),后面可跟多个参数(用逗号分隔)。
-
核心规则:
函数名(参数1, 参数2, ...),操作数 = 函数名 + 所有参数 -
例子:
printf("hi"):操作数是printf和"hi" -
add(3,5):操作数是add、3、5
代码示例:函数调用操作符
#include <stdio.h>
// 加法函数
int add(int x, int y) {
return x + y;
}
// 无参函数
void test() {
printf("函数调用成功✨\n");
}
int main()
{
printf("Hello C!\n"); // 操作数:printf、"Hello C!" → 输出Hello C!
int c = add(3, 5); // 操作数:add、3、5 → c=8
test(); // 操作数:test → 输出函数调用成功✨
printf("3+5=%d\n", c); // 输出3+5=8
return 0;
}
写在最后
🎉 到这里,移位操作符、位操作符(这俩是重点,一定要多练)、逗号表达式,还有数组/函数调用操作符就全掌握啦!这些知识点不是纸上谈兵——移位和位操作符在嵌入式、算法中能解决很多实际问题,逗号表达式和调用操作符则是提升代码简洁性的基础。
下一篇我们将攻克更实用的内容:结构体成员访问操作符(.和->,处理结构体必备)、操作符的优先级与结合性(避免踩优先级的坑),还有表达式求值的常见陷阱(很多人栽在这里!),记得持续关注哦~
更多推荐



所有评论(0)