操作符详解:从入门到精通

操作符详解:从入门到精通 操作符详解从入门到精通前言操作符是C语言的灵魂掌握好操作符的使用就能写出更加高效、优雅的代码。本文将全面系统地讲解C语言中的各类操作符包括它们的分类、使用方法和注意事项帮助你彻底搞懂操作符的方方面面。1. 操作符的分类C语言中的操作符非常丰富大致可以分为以下几类类别操作符算术操作符-*/%移位操作符位操作符赋值操作符-*/%单目操作符!--*-~sizeof(类型)关系操作符!逻辑操作符条件操作符?:逗号表达式,下标引用[]函数调用()结构成员访问.-今天我们将重点介绍与二进制相关的操作符移位、位操作符以及其他尚未详细讲解的操作符。2. 二进制与进制转换在深入位操作符之前我们需要先了解二进制的基础知识。2.1 什么是进制2进制、8进制、10进制、16进制只是数值的不同表示形式。比如数值152进制11118进制17以0开头10进制1516进制F以0x开头2.2 2进制转10进制2进制每一位都有权重从右向左依次是(2^0, 2^1, 2^2, \ldots)例如二进制1101 (1 \times 8 1 \times 4 0 \times 2 1 \times 1 13)2.3 10进制转2进制使用除2取余法不断除以2将余数从下往上排列。例如125转换为2进制 →11111012.4 2进制转8进制和16进制转8进制从右向左每3位一组转换为对应的8进制数字最高位不足3位时直接转换转16进制从右向左每4位一组转换为对应的16进制数字 小贴士8进制数以0开头16进制数以0x开头。3. 原码、反码、补码整数的二进制表示有三种形式原码、反码、补码。3.1 基本规则类型符号位正数负数原码最高位0正1负同原码数值位不变反码不变同原码符号位不变数值位取反补码不变同原码反码1重要整数在内存中存储的是补码3.2 为什么用补码符号位和数值位可以统一处理加法和减法可以统一处理CPU只有加法器补码与原码的转换过程相同不需要额外硬件4. 移位操作符移位操作符的操作数只能是整数。4.1 左移操作符规则左边抛弃右边补0intnum10;// 二进制1010intnnum1;// 结果10100 204.2 右移操作符右移分为两种类型规则逻辑右移左边补0右边丢弃算术右移左边补符号位右边丢弃⚠️警告不要移动负数位如num -1是未定义行为5. 位操作符、|、^、~位操作符的操作数必须是整数。操作符名称规则按位与对应位都是1结果为1按位或^按位异或对应位不同结果为1~按位取反0变11变0intnum1-3;intnum25;printf(%d\n,num1num2);// 按位与printf(%d\n,num1|num2);// 按位或printf(%d\n,num1^num2);// 按位异或printf(%d\n,~0);// 按位取反5.1 经典面试题不创建临时变量交换两个整数inta10,b20;aa^b;ba^b;// b (a ^ b) ^ b aaa^b;// a (a ^ b) ^ a bprintf(a %d, b %d\n,a,b);原理异或运算满足自反性(a ^ b) ^ b a5.2 练习1求二进制中1的个数方法1有缺陷不能处理负数while(num){if(num%21)count;num/2;}方法2循环32次for(i0;i32;i){if(num(1i))count;}方法3最优解while(num){count;numnum(num-1);// 每次消去最右边的1}num (num - 1)这个技巧非常经典可以快速消去二进制中最右边的1。5.3 练习2二进制位置0或置1将13的第5位从0开始计数修改为1再改回0inta13;// 第5位置为1aa|(14);// 第5位置为0aa~(14);6. 单目操作符单目操作符的特点是只有一个操作数操作符名称说明!逻辑反真变假假变真自增前置或后置--自减前置或后置取地址获取变量的地址*解引用通过地址访问变量正号正数-负号负数~按位取反二进制位取反sizeof取大小计算类型或变量的大小(类型)强制类型转换转换数据类型7. 逗号表达式逗号表达式从左向右依次执行整个表达式的结果是最后一个表达式的结果。inta1,b2;intc(ab,ab10,a,ba1);// c的结果是 b a 1 13// 实用场景简化while循环while(aget_val(),count_val(a),a0){// 业务处理}8. 下标访问与函数调用8.1 下标引用操作符[]操作数数组名 索引值intarr[10];// 创建数组arr[9]10;// [] 的操作数是 arr 和 98.2 函数调用操作符()操作数函数名 传递给函数的参数test1();// () 的操作数是 test1test2(hello);// () 的操作数是 test2 和 hello9. 结构成员访问操作符9.1 结构体声明structStu{charname[20];// 名字intage;// 年龄charsex[5];// 性别charid[20];// 学号};9.2 直接访问.structStus{张三,20};printf(%s %d\n,s.name,s.age);9.3 间接访问-structStu*ptrs;ptr-age21;// 等价于 (*ptr).age 2110. 操作符的优先级与结合性10.1 优先级优先级决定哪个运算符先执行。乘法优先级高于加法34*5;// 先算 4*520再加3得2310.2 结合性当优先级相同时结合性决定执行顺序左结合从左到右执行大部分运算符右结合从右到左执行赋值运算符等5*6/2;// 左结合先算5*630再除以2得1510.3 常用优先级速查表优先级运算符结合性1最高()[].-左到右2--*-~!sizeof右到左3*/%左到右4-左到右5左到右6左到右7!左到右8左到右9^左到右1011左到右1213?:右到左14及复合赋值右到左15最低,左到右建议记不住优先级没关系使用圆括号()明确表达式的计算顺序即可11. 表达式求值的陷阱11.1 整型提升C语言中char、short等类型在进行算术运算时会先转换为int或unsigned int这就是整型提升。提升规则有符号数按符号位提升无符号数高位补0chara,b,c;abc;// b和c先提升为int计算后再截断存入a11.2 算术转换当操作数类型不同时会进行算术转换向更高精度转换long double double float unsigned long long unsigned int int11.3 问题表达式有些表达式虽然语法正确但计算结果不确定应避免写出// 问题1操作数的求值顺序不确定a*bc*de*f;// 问题2i的修改和读取顺序不确定c--c;// 问题3函数调用顺序不确定fun()-fun()*fun();// 问题4不同编译器结果不同intret(i)(i)(i);⚠️核心原则不要写出过于复杂的表达式保持代码清晰、可读性强总结本文全面介绍了C语言中的各类操作符包括进制转换理解二进制、八进制、十六进制原反补码理解整数在内存中的存储移位和位操作高效处理二进制位优先级与结合性理解表达式求值顺序常见陷阱避免写出有歧义的表达式掌握好这些知识你就能写出更加高效、准确的C语言代码。记住简单清晰的代码比巧妙的代码更有价值如果觉得这篇文章对你有帮助欢迎点赞、收藏、分享