C++ 运算符全解析:算术、关系、逻辑与位运算
运算符是C++编程的基础语法元素,用于对数据进行运算、比较、逻辑判断及位操作等操作。掌握不同类型运算符的用法、优先级与结合性,是编写高效、无bug代码的核心前提。本文将系统拆解C++中最常用的四大类运算符------算术运算符、关系运算符、逻辑运算符与位运算符,结合实例讲解其语法规则、使用场景及常见误区,帮助开发者彻底吃透运算符的核心用法。
一、算术运算符:数值计算的基础
算术运算符用于对数值类型(int、float、double等)数据执行加减乘除、取余等基本运算,部分运算符支持前缀/后缀形式,语义存在细微差异。
1. 基本算术运算符
C++提供6种基本算术运算符,涵盖基础数值运算场景,具体如下表所示:
| 运算符 | 名称 | 功能描述 | 示例 | 结果 |
|---|---|---|---|---|
| + | 加法 | 两数相加,也可作为正号运算符 | 3 + 5 / +7 | 8 / 7 |
| - | 减法 | 两数相减,也可作为负号运算符 | 10 - 4 / -3 | 6 / -3 |
| * | 乘法 | 两数相乘 | 4 * 6 | 24 |
| / | 除法 | 两数相除,整数除法会舍弃小数部分 | 15 / 4 / 15.0 / 4 | 3 / 3.75 |
| % | 取余(模运算) | 返回两整数相除后的余数,结果符号与被除数一致 | 15 % 4 / -15 % 4 | 3 / -3 |
2. 自增自减运算符(++/--)
自增(++)、自减(--)运算符用于将变量值加1或减1,支持前缀(++a)和后缀(a++)两种形式,核心区别在于运算顺序:
-
前缀形式:先修改变量值,再使用变量参与其他运算;
-
后缀形式:先使用变量当前值参与运算,再修改变量值。
cpp
#include <iostream>
using namespace std;
int main() {
int a = 5, b = 5;
int c = ++a; // 前缀自增:a先变为6,再赋值给c,c=6,a=6
int d = b++; // 后缀自增:先将b=5赋值给d,再b变为6,d=5,b=6
cout << "c = " << c << ", a = " << a << endl; // 输出:c = 6, a = 6
cout << "d = " << d << ", b = " << b << endl; // 输出:d = 5, b = 6
return 0;
}
注意:自增自减运算符仅能作用于变量,不能作用于常量或表达式(如++5、(a+b)++均为语法错误)。
3. 算术运算的常见误区
-
整数除法精度丢失:当两个整数相除时,C++会自动舍弃小数部分,而非四舍五入。若需保留小数,需将其中一个操作数转为浮点数(如15.0 / 4 而非15 / 4)。
-
取余运算的符号问题:结果符号与被除数一致,而非除数。例如-15 % 4 = -3,15 % -4 = 3。
-
自增自减的嵌套使用:避免在同一表达式中多次使用自增自减(如a = ++a + a++),不同编译器对运算顺序的解析可能不同,导致结果不确定。
二、关系运算符:判断数据间的逻辑关系
关系运算符用于比较两个数据的大小或相等关系,返回值为布尔类型(bool),即true(1)或false(0)。关系运算符是条件判断(if、while等语句)的核心组成部分。
1. 关系运算符列表
| 运算符 | 名称 | 功能描述 | 示例 | 结果 |
|---|---|---|---|---|
| == | 等于 | 判断两个操作数是否相等 | 3 == 5 | false |
| != | 不等于 | 判断两个操作数是否不相等 | 3 != 5 | true |
| > | 大于 | 判断左操作数是否大于右操作数 | 7 > 2 | true |
| < | 小于 | 判断左操作数是否小于右操作数 | 7 < 2 | false |
| >= | 大于等于 | 判断左操作数是否大于或等于右操作数 | 5 >= 5 | true |
| <= | 小于等于 | 判断左操作数是否小于或等于右操作数 | 5 <= 3 | false |
2. 核心使用要点
cpp
#include <iostream>
using namespace std;
int main() {
int a = 10, b = 20;
cout << (a == b) << endl; // 0(false)
cout << (a != b) << endl; // 1(true)
cout << (a >= 5) << endl; // 1(true)
// 关系表达式可直接作为条件判断
if (a < b) {
cout << "a小于b" << endl; // 执行此语句
}
return 0;
}
关键注意事项:
-
区分""与"=":""是关系运算符(判断相等),"="是赋值运算符(给变量赋值),误写会导致逻辑错误(如if (a = 5) 会将5赋值给a,且表达式结果恒为true)。
-
浮点数比较需谨慎:由于浮点数存在精度误差(如0.1 + 0.2 ≈ 0.30000000000000004),不能直接用"=="判断相等,需通过比较两数差值的绝对值是否小于极小值(如1e-9)来实现。
三、逻辑运算符:组合条件的逻辑判断
逻辑运算符用于对布尔值进行逻辑运算,实现多条件的组合判断,返回值仍为bool类型。C++支持三种逻辑运算符,且均支持"短路求值"特性,这是优化代码性能与避免异常的关键。
1. 逻辑运算符详解
| 运算符 | 名称 | 功能描述 | 短路求值规则 | 示例 |
|---|---|---|---|---|
| & | 逻辑与 | 两操作数均为true时,结果为true;否则为false | 左操作数为false时,不计算右操作数 | (3>2) && (5<10) → true |
| 逻辑或 | 两操作数至少一个为true时,结果为true;否则为false | |||
| ! | 逻辑非 | 对操作数取反,true变false,false变true | 无短路特性(仅单操作数) | !(3>2) → false |
2. 短路求值的应用与注意
短路求值可减少不必要的运算,同时避免因右操作数异常导致的程序错误,是逻辑运算符的核心特性:
cpp
#include <iostream>
using namespace std;
int main() {
int a = 5, b = 10;
// 逻辑与:左为false,右操作数a++不执行,a仍为5
if (a > 10 && a++) {
cout << "执行逻辑与内语句" << endl;
}
cout << "a = " << a << endl; // 输出:a = 5
// 逻辑或:左为true,右操作数b--不执行,b仍为10
if (a < 10 || b--) {
cout << "执行逻辑或内语句" << endl; // 执行此语句
}
cout << "b = " << b << endl; // 输出:b = 10
return 0;
}
注意:避免在逻辑表达式中嵌入具有副作用的操作(如自增、赋值),否则可能因短路求值导致预期外的结果。
四、位运算符:直接操作二进制位
位运算符用于对整数类型数据的二进制位进行直接操作,包括移位、按位与/或/异或/取反等。位运算效率极高,常用于底层开发、算法优化、权限控制等场景,但需熟悉二进制运算规则。
1. 位运算符列表(仅作用于整数类型)
| 运算符 | 名称 | 功能描述 | 示例(a=6即0110,b=3即0011) | 结果(二进制/十进制) |
|---|---|---|---|---|
| 按位与 | 对应位均为1时,结果位为1;否则为0 | a & b | 0010 / 2 | |
| 按位或 | 对应位至少一个为1时,结果位为1;否则为0 | a | ||
| ^ | 按位异或 | 对应位不同时,结果位为1;相同时为0 | a ^ b | 0101 / 5 |
| ~ | 按位取反 | 对所有位取反(0变1,1变0),符号位也取反 | ~a | 1001(补码) / -7 |
| << | 左移 | 所有位向左移n位,右侧补0,左侧溢出位舍弃(相当于乘以2ⁿ) | a << 1 | 1100 / 12 |
| >> | 右移 | 正数:所有位向右移n位,左侧补0;负数:左侧补符号位(相当于除以2ⁿ,向下取整) | a >> 1 | 0011 / 3 |
2. 位运算的典型应用场景
cpp
#include <iostream>
using namespace std;
int main() {
// 1. 按位异或:交换两个变量(无需临时变量)
int a = 6, b = 3;
a = a ^ b;
b = a ^ b; // 等价于 b = (a^b) ^ b = a
a = a ^ b; // 等价于 a = (a^b) ^ a = b
cout << "a = " << a << ", b = " << b << endl; // 输出:a = 3, b = 6
// 2. 左移/右移:高效乘除2的幂
int c = 8;
cout << (c << 2) << endl; // 8*4=32
cout << (c >> 1) << endl; // 8/2=4
// 3. 按位与:判断奇偶数(末位为1则为奇数)
int d = 7;
if (d & 1) {
cout << d << "是奇数" << endl; // 执行此语句
}
return 0;
}
注意:位运算仅适用于整数类型,不可用于浮点数;右移运算对负数的处理因编译器而异,需谨慎使用。
五、运算符优先级与结合性
当多个运算符在同一表达式中混合使用时,优先级决定运算顺序,结合性决定优先级相同时的运算方向,这是避免表达式结果异常的关键规则。
1. 核心优先级排序(从高到低)
-
位取反(~)、逻辑非(!)、自增自减(++/--)、正负号(+/-):单目运算符,优先级最高;
-
算术运算符:先乘除取余(*、/、%),后加减(+、-);
-
位运算符:左移/右移(<<、>>)高于按位与(&),按位与高于按位异或(^),按位异或高于按位或(|);
-
关系运算符(==、!=、>、<、>=、<=);
-
逻辑运算符:逻辑与(&&)高于逻辑或(||);
-
赋值运算符(=、+=、-=等):优先级最低。
2. 结合性规则
-
单目运算符、赋值运算符:右结合(从右向左运算),如a = b = 5 等价于 a = (b = 5);
-
其他运算符(算术、关系、逻辑、位运算):左结合(从左向右运算),如a + b - c 等价于 (a + b) - c。
技巧:无论优先级如何,复杂表达式建议通过括号明确运算顺序,既避免错误,又提升代码可读性(如(a + b) * c 而非a + b * c)。
六、总结
C++运算符看似基础,却涵盖丰富的语法细节与使用场景:算术运算符是数值计算的基石,关系与逻辑运算符支撑条件判断,位运算则为底层优化提供可能。掌握运算符的核心要点需注意三点:一是明确各类运算符的语法与语义,二是理解短路求值、优先级、结合性等特性,三是规避整数除法精度丢失、浮点数比较、自增自减嵌套等常见误区。
在实际开发中,应根据场景选择合适的运算符,兼顾代码的正确性、高效性与可读性。熟练运用运算符,是编写高质量C++代码的重要基础。