C++ 运算符
C++ 中的运算符
Section titled “C++ 中的运算符”运算符(operator)是一个符号,它指示编译器执行特定的数学、逻辑或操作运算。C++ 提供了一套丰富的内置运算符,主要分类如下:
- 算术运算符 (Arithmetic Operators)
- 关系运算符 (Relational Operators)
- 逻辑运算符 (Logical Operators)
- 位运算符 (Bitwise Operators)
- 赋值运算符 (Assignment Operators)
- 杂项运算符 (Miscellaneous Operators)(包括三元条件运算符、sizeof、类型转换、指针等)
本章将探讨这些运算符。
这些运算符执行标准的数学计算。
假设 int a = 10; 且 int b = 20;
| 运算符 | 名称 | 描述 | 示例 |
|---|---|---|---|
| + | 加法 | 将两个操作数相加 | a + b // 结果是 30 |
| - | 减法 | 用第一个操作数减去第二个操作数 | b - a // 结果是 10 |
| * | 乘法 | 将两个操作数相乘 | a * b // 结果是 200 |
| / | 除法 | 用第一个操作数除以第二个操作数。如果两个操作数都是整数,则结果为整数。 | b / a // 结果是 2 |
| % | 取模 | 计算整数除法的余数 | b % a // 结果是 0 |
| ++ | 自增 | 将整数值增加一。前置自增 (++a) 在使用前增加,后置自增 (a++) 在使用后增加。 | ++a // a 变为 11, 结果是 11 a++ // a 变为 11, 结果是 10 (原始值) |
| — | 自减 | 将整数值减少一。前置/后置行为与自增类似。 | —a // a 变为 9, 结果是 9 a— // a 变为 9, 结果是 10 (原始值) |
这些运算符比较两个操作数并返回一个布尔值 (true 或 false)。
假设 int a = 10; 且 int b = 20;
| 运算符 | 名称 | 描述 | 示例 |
|---|---|---|---|
| == | 等于 | 检查两个操作数的值是否相等。 | (a == b) // 假 |
| != | 不等于 | 检查两个操作数的值是否不相等。 | (a != b) // 真 |
| > | 大于 | 检查左操作数的值是否大于右操作数。 | (a > b) // 假 |
| < | 小于 | 检查左操作数的值是否小于右操作数。 | (a < b) // 真 |
| >= | 大于或等于 | 检查左操作数的值是否大于或等于右操作数。 | (a >= b) // 假 |
| <= | 小于或等于 | 检查左操作数的值是否小于或等于右操作数。 | (a <= b) // 真 |
注意:C++20 引入了三路比较运算符 (<=>),也称为飞船运算符 (spaceship operator),它可以简化比较逻辑,但这些基本运算符仍然是必不可少的。
这些运算符作用于布尔操作数,通常用于组合关系表达式。
假设 bool condition1 = true; 且 bool condition2 = false;
| 运算符 | 名称 | 描述 | 示例 |
|---|---|---|---|
| && | 逻辑与 | 仅当两个操作数都为 true 时,结果才为 true。使用短路求值(如果第一个操作数为 false,则不评估第二个)。 | (condition1 && condition2) // 假 |
| || | 逻辑或 | 如果至少有一个操作数为 true,则结果为 true。使用短路求值(如果第一个操作数为 true,则不评估第二个)。 | (condition1 || condition2) // 真 |
| ! | 逻辑非 | 反转操作数的逻辑状态。true 变为 false,false 变为 true。 | !condition1 // 假 !condition2 // 真 |
这些运算符直接操作整数操作数的二进制(位)表示。
基本位运算的真值表:
| p | q | p & q (AND) | p | q (OR) | p ^ q (XOR) |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 |
| 0 | 1 | 0 | 1 | 1 |
| 1 | 1 | 1 | 1 | 0 |
| 1 | 0 | 0 | 1 | 1 |
假设 unsigned int a = 60;(二进制 0011 1100)且 unsigned int b = 13;(二进制 0000 1101)。使用 unsigned int 可以避免此示例中的符号扩展复杂性。
a = 0011 1100b = 0000 1101-----------------a & b = 0000 1100 (十进制 12)a | b = 0011 1101 (十进制 61)a ^ b = 0011 0001 (十进制 49)~a = 1100 0011 (取决于 int 大小和符号性;对于无符号 8 位:195。对于使用二进制补码的有符号 8 位,它可能表示 -61)| 运算符 | 名称 | 描述 | 示例 (使用 a=60, b=13) |
|---|---|---|---|
| & | 按位与 | 如果两个操作数中都存在某位,则将该位复制到结果中。 | (a & b) // 结果是 12 (0000 1100) |
| | | 按位或 | 如果任一操作数中存在某位,则将该位复制。 | (a | b) // 结果是 61 (0011 1101) |
| ^ | 按位异或 | 如果仅在一个操作数中设置了某位,则复制该位。 | (a ^ b) // 结果是 49 (0011 0001) |
| ~ | 按位取反 | 一元运算符;翻转其操作数的所有位。 | (~a) // 结果取决于整数大小和符号性。对于 32 位无符号 int,它是一个很大的正数。对于有符号 int,通常由于二进制补码而导致结果为 -(a+1)。 |
| << | 左移 | 将左操作数的位向左移动右操作数指定的位数。用零填充空出的位。 | a << 2 // 结果是 240 (1111 0000) |
| >> | 右移 | 将左操作数的位向右移动。对于有符号类型,最左侧空出的位的行为是实现定义的(通常是符号位复制 - 算术右移),而无符号类型用零填充(逻辑右移)。 | a >> 2 // 结果是 15 (0000 1111) |
这些运算符将值赋给变量。复合赋值运算符提供了常见操作的简写形式。
假设 int c = 0; int a = 10; int b = 20;
| 运算符 | 名称 | 描述 | 示例 |
|---|---|---|---|
| = | 简单赋值 | 将右操作数的值赋给左操作数。 | c = a + b; // c 变为 30 |
| += | 加并赋值 | 将右操作数加到左操作数,并将结果赋给左操作数。 | c += a; // 等同于 c = c + a; |
| -= | 减并赋值 | 从左操作数中减去右操作数,并将结果赋给左操作数。 | c -= a; // 等同于 c = c - a; |
| *= | 乘并赋值 | 将左操作数乘以右操作数,并将结果赋给左操作数。 | c *= a; // 等同于 c = c * a; |
| /= | 除并赋值 | 将左操作数除以右操作数,并将结果赋给左操作数。 | c /= a; // 等同于 c = c / a; |
| %= | 取模并赋值 | 使用两个操作数计算模,并将结果赋给左操作数。 | c %= a; // 等同于 c = c % a; |
| <<= | 左移并赋值 | 执行按位左移并赋值。 | c <<= 2; // 等同于 c = c << 2; |
| >>= | 右移并赋值 | 执行按位右移并赋值。 | c >>= 2; // 等同于 c = c >> 2; |
| &= | 按位与并赋值 | 执行按位与并赋值。 | c &= a; // 等同于 c = c & a; |
| ^= | 按位异或并赋值 | 执行按位异或并赋值。 | c ^= a; // 等同于 c = c ^ a; |
| |= | 按位或并赋值 | 执行按位或并赋值。 | c |= a; // 等同于 c = c | a; |
C++ 中的其他重要运算符:
| 运算符 | 名称 | 描述 | 示例 |
|---|---|---|---|
sizeof | sizeof 运算符 | 返回数据类型或变量的大小(以字节为单位)。结果类型是 size_t。大小可能因平台/编译器而异。 | sizeof(int) // 返回 int 的大小(例如,4)sizeof(myVariable) // 返回 myVariable 的大小 |
?: | 三元条件运算符 | 语法:条件 ? ValueIfTrue : ValueIfFalse。评估条件。如果为 true,则返回 ValueIfTrue;否则,返回 ValueIfFalse。 | int maxVal = (a > b) ? a : b; |
, | 逗号运算符 | 顺序评估多个表达式,从左到右。整个表达式的结果是最右边表达式的值。常用于 for 循环中。 | x = (a++, b++); // 先递增 a,然后递增 b,最后将 b 的原始值赋给 x |
. (点) 和 -> (箭头) | 成员访问运算符 | . 用于访问对象的成员(变量或函数)。-> 用于通过指向对象的指针访问成员。 | myObject.membermyPointer->member (等同于 (*myPointer).member) |
| Casting Operators | 类型转换 | 将一个数据类型的值转换为另一个。现代 C++ 更倾向于显式转换:static_cast、dynamic_cast、const_cast、reinterpret_cast。避免使用 C 风格转换 ((type)value 或 type(value))。 | int i = static_cast<int>(2.718); // i 变为 2float f = static_cast<float>(i); |
& | 取地址运算符 | 一元运算符;返回其操作数的内存地址。 | int* ptr = &myVariable; // ptr 存储 myVariable 的地址 |
* | 解引用运算符 | 一元运算符;访问指针所持有的内存地址处存储的值。 | int value = *ptr; // value 获取 ptr 指向的内容 |
C++ 中的运算符优先级
Section titled “C++ 中的运算符优先级”运算符优先级决定了表达式中运算符的评估顺序。优先级较高的运算符在优先级较低的运算符之前被评估。结合性定义了具有相同优先级的运算符的评估顺序(从左到右或从右到左)。
例如,在 x = 7 + 3 * 2; 中,乘法 (*) 的优先级高于加法 (+),因此先评估 3 * 2(结果为 6),然后是 7 + 6(结果为 13)。x 变为 13。
使用括号 () 来覆盖优先级或提高清晰度:x = (7 + 3) * 2; 将导致 x 为 20。
以下是 C++ 运算符优先级(从高到低)和结合性的总结:
| 类别 | 运算符 | 结合性 |
|---|---|---|
| 作用域解析 (Scope Resolution) | :: | 从左到右 |
| 后缀/主运算符 (Postfix/Primary) | () [] . -> ++ -- typeid static_cast dynamic_cast const_cast reinterpret_cast | 从左到右 |
| 一元/前缀运算符 (Unary/Prefix) | + - ! ~ ++ -- * & sizeof new delete (type) noexcept alignof | 从右到左 |
| 成员指针访问 (Member Pointer Access) | .* ->* | 从左到右 |
| 乘法类运算符 (Multiplicative) | * / % | 从左到右 |
| 加法类运算符 (Additive) | + - | 从左到右 |
| 移位运算符 (Shift) | << >> | 从左到右 |
| 三路比较 (C++20) (Three-way comparison) | <=> | 从左到右 |
| 关系运算符 (Relational) | < <= > >= | 从左到右 |
| 相等性运算符 (Equality) | == != | 从左到右 |
| 按位与 (Bitwise AND) | & | 从左到右 |
| 按位异或 (Bitwise XOR) | ^ | 从左到右 |
| 按位或 (Bitwise OR) | | | 从左到右 |
| 逻辑与 (Logical AND) | && | 从左到右 |
| 逻辑或 (Logical OR) | || | 从左到右 |
| 条件运算符 (三元) (Conditional (Ternary)) | ?: | 从右到左 |
| 赋值运算符 (Assignment) | = += -= *= /= %= <<= >>= &= ^= |= | 从右到左 |
| Throw 表达式 (Throw expression) | throw | 从右到左 |
| 逗号运算符 (Comma) | , | 从左到右 |
有关权威的优先级表,请参阅 cppreference.com 等资源。如有疑问,请使用括号!