运算

编程语言 / op

本地源文件:docs/lang__op.md

运算

算术运算符

运算符功能
+ (单目)
- (单目)
* (双目)乘法
/除法
%取模
+ (双目)加法
- (双目)减法

单目与双目运算符

单目运算符(又称一元运算符)指被操作对象只有一个的运算符,而双目运算符(又称二元运算符)的被操作对象有两个.例如 1 + 2 中加号就是双目运算符,它有 12 两个被操作数.此外 C++ 中还有唯一的一个三目运算符 ?:

算术运算符中有两个单目运算符(正、负)以及五个双目运算符(乘法、除法、取模、加法、减法),其中单目运算符的优先级最高.

其中取模运算符 % 意为计算两个整数相除得到的余数,即求余数.

- 为双目运算符时做减法运算符,如 2-1 ;为单目运算符时做负值运算符,如 -1

使用方法如下

op=x-y*z

得到的 op 的运算值遵循数学中加减乘除的优先规律,首先进行优先级高的运算,同优先级按运算的结合性运算,括号提高优先级.

算术运算中的类型转换

对于双目算术运算符,当参与运算的两个变量类型相同时,不发生 类型转换,运算结果将会用参与运算的变量的类型容纳,否则会发生类型转换,以使两个变量的类型一致.转换的规则参见 类型转换

例如,对于一个整型(int)变量 𝑥x 和另一个双精度浮点型(double)类型变量 𝑦y

  • x/3 的结果将会是整型;
  • x/3.0 的结果将会是双精度浮点型;
  • x/y 的结果将会是双精度浮点型;
  • x*1/3 的结果将会是整型;
  • x*1.0/3 的结果将会是双精度浮点型;

位操作符

另请参阅:位运算

运算符功能
~逐位非
& (双目)逐位与

|| 逐位或 ^| 逐位异或 <<| 逐位左移 >>| 逐位右移

位操作的意义请参考 位操作 页面.需要注意的是,位操作的优先级低于算术运算符(除了取反),而按位与、按位或及异或低于比较运算符(详见 C++ 运算符优先级总表),所以使用时需多加注意,在必要时添加括号.

移位运算中如果出现如下情况,则其行为未定义:

  1. 右操作数(即移位数)为负值;
  2. 右操作数大于等于左操作数的位数;

例如,对于 int32_t 类型的变量 aa<<-1a<<32 都是未定义的.

对于带符号非负数的左移操作,需要确保移位后的结果能被原数的类型容纳,否则行为也是未定义的.1对一个负数执行左移操作也未定义.2

对于右移操作,右侧多余的位将会被舍弃,而左侧较为复杂:对于无符号数,会在左侧补 003;而对于有符号数,则会用最高位的数(其实就是符号位,非负数为 00,负数为 11)补齐4.

自增/自减 运算符

有时我们需要让变量进行增加 1(自增)或者减少 1(自减),这时自增运算符 ++ 和自减运算符 -- 就派上用场了.

自增/自减运算符可放在变量前或变量后面,在变量前称为前缀,在变量后称为后缀,单独使用时前缀后缀无需特别区别,如果需要用到表达式的值则需注意,具体可看下面的例子.详细情况可参考 引用 介绍的例子部分.

---|---

## 复合赋值运算符

复合赋值运算符实际上是表达式的缩写形式.可分为复合算术运算符 `+=`、`-=`、`*=`、`/=`、`%=` 和复合位操作符 `&=`、`|=`、`^=`、`<<=`、`>>=`.

例如,`op = op + 2` 可写为 `op += 2`,`op = op - 2` 可写为 `op -= 2`,`op= op * 2` 可写为 `op *= 2`.

## 条件运算符

条件运算符可以看作 `if` 语句的简写,`a ? b : c` 中如果表达式 `a` 成立,那么这个条件表达式的结果是 `b`,否则条件表达式的结果是 `c`.

## 比较运算符

运算符| 功能
---|---
`>`| 大于
`>=`| 大于等于
`<`| 小于
`<=`| 小于等于
`==`| 等于
`!=`| 不等于

其中特别需要注意的是要将等于运算符 `==` 和赋值运算符 `=` 区分开来,这在判断语句中尤为重要.

`if (op=1)` 与 `if (op==1)` 看起来类似,但实际功能却相差甚远.第一条语句是在对 op 进行赋值,若赋值为非 0 时为真值,表达式的条件始终是满足的,无法达到判断的作用;而第二条语句才是对 `op` 的值进行判断.

## 逻辑运算符

运算符| 功能
---|---
`&&`| 逻辑与
`||`| 逻辑或
`!`| 逻辑非

---|---

内建的 运算符 &&|| 进行短路求值(若在求值第一个操作数后结果已知,则不求值第二个),重载的运算符无此特性,并始终对两个操作数都进行求值.

逗号运算符

逗号运算符可将多个表达式分隔开来,被分隔开的表达式按从左至右的顺序依次计算,整个表达式的值是最后的表达式的值.逗号表达式的优先级在所有运算符中的优先级是 最低 的.

---|---

## 成员访问运算符

运算符| 功能
---|---
`[]`| 数组下标
`.`| 对象成员
`&` (单目)| 取地址/获取引用
`*` (单目)| 间接寻址/解引用
`->`| 指针成员

这些运算符用来访问对象的成员或者内存,除了最后一个运算符外上述运算符都可被重载.与 `&` , `*` 和 `->` 相关的内容请阅读 [指针](../pointer/) 和 [引用](../reference/) 教程.这里还省略了两个很少用到的运算符 `.*` 和 `->*` ,其具体用法可以参见 [C++ 语言手册](https://zh.cppreference.com/w/cpp/language/operator_member_access) .

---|---

C++ 运算符优先级总表

来自 C++ 运算符优先级 - cppreference ,有修改.

运算符描述例子可重载性
第一级别
::作用域解析符Class::age = 2;不可重载
第二级别
++后自增运算符for (int i = 0; i < 10; i++) cout << i;可重载
--后自减运算符for (int i = 10; i > 0; i--) cout << i;可重载
type() type{}强制类型转换unsigned int a = unsigned(3.14);可重载
()函数调用isdigit('1')可重载
[]数组数据获取array[4] = 2;可重载
.对象型成员调用obj.age = 34;不可重载
->指针型成员调用ptr->age = 34;可重载
第三级别 (从右向左结合)
++前自增运算符for (i = 0; i < 10; ++i) cout << i;可重载
--前自减运算符for (i = 10; i > 0; --i) cout << i;可重载
+正号int i = +1;可重载
-负号int i = -1;可重载
!逻辑取反if (!done) …可重载
~按位取反flags = ~flags;可重载
(type)C 风格强制类型转换int i = (int) floatNum;可重载
*指针取值int data = *intPtr;可重载
&值取指针int *intPtr = &data可重载
sizeof返回类型内存int size = sizeof floatNum; int size = sizeof(float);不可重载
new动态元素内存分配long pVar = new long; MyClass ptr = new MyClass(args);可重载
new []动态数组内存分配long *array = new long[n];可重载
delete动态析构元素内存delete pVar;可重载
delete []动态析构数组内存delete [] array;可重载
第四级别
.*类对象成员引用obj.*var = 24;不可重载
->*类指针成员引用ptr->*var = 24;可重载
第五级别
*乘法int i = 2 * 4;可重载
/除法float f = 10.0 / 3.0;可重载
%取余数(模运算)int rem = 4 % 3;可重载
第六级别
+加法int i = 2 + 3;可重载
-减法int i = 5 - 1;可重载
第七级别
<<位左移int flags = 33 << 1;可重载
>>位右移int flags = 33 >> 1;可重载
第八级别
<=>三路比较运算符if ((i <=> 42) < 0) ...可重载
第九级别
<小于if (i < 42) ...可重载
<=小于等于if (i <= 42) ...可重载
>大于if (i > 42) ...可重载
>=大于等于if (i >= 42) ...可重载
第十级别
==等于if (i == 42) ...可重载
!=不等于if (i != 42) ...可重载
第十一级别
&位与运算flags = flags & 42;可重载
第十二级别
^位异或运算flags = flags ^ 42;可重载
第十三级别

|| 位或运算| flags = flags | 42;| 可重载 第十四级别| | | &&| 逻辑与运算| if (conditionA && conditionB) ...| 可重载 第十五级别| | | ||| 逻辑或运算| if (conditionA || conditionB) ...| 可重载 第十六级别 (从右向左结合)| | | ? :| 条件运算符| int i = a > b ? a : b;| 不可重载 throw| 异常抛出| throw EClass("Message");| 不可重载 =| 赋值| int a = b;| 可重载 +=| 加赋值运算| a += 3;| 可重载 -=| 减赋值运算| b -= 4;| 可重载 =| 乘赋值运算| a = 5;| 可重载 /=| 除赋值运算| a /= 2;| 可重载 %=| 模赋值运算| a %= 3;| 可重载 <<=| 位左移赋值运算| flags <<= 2;| 可重载 >>=| 位右移赋值运算| flags >>= 2;| 可重载 &=| 位与赋值运算| flags &= new_flags;| 可重载 ^=| 位异或赋值运算| flags ^= new_flags;| 可重载 |=| 位或赋值运算| flags |= new_flags;| 可重载 第十七级别| | | ,| 逗号分隔符| for (i = 0, j = 0; i < 10; i++, j++) ...| 可重载

需要注意的是,表中并未列出 const_caststatic_castdynamic_castreinterpret_casttypeidsizeof...noexceptalignof 等运算符,因为它们的使用形式与函数调用相同,不会出现歧义.

参考资料与注释

  1. C++20 前,若原值为带符号类型,且移位后的结果能被原类型的无符号版本容纳,则将该结果 转换 为相应的带符号值,否则行为未定义;无符号数的左移则舍弃移出结果类型的位.C++20 起,规定 a << b 为 𝑎 ⋅2𝑏a⋅2b 在模 2𝑁2N 下的值(𝑁N 为结果类型的位宽),即无论是带符号数还是无符号数,左移均直接舍弃移出结果类型的位(即 算术左移/逻辑左移). ↩↩
  1. C++20 前.C++20 起的行为参见1. ↩
  1. 逻辑右移. ↩
  1. 算术右移.C++20 前,带符号的右移是依实现定义的,在大多数实现中,均采用算术右移.C++20 起,规定 a >> b 为 ⌊𝑎/2𝑏⌋⌊a/2b⌋,所以带符号数右移运算是算术右移. ↩
本页面最近更新: 2026/1/27 12:26:08,更新历史 发现错误?想一起完善?在 GitHub 上编辑此页! 本页面贡献者:ouuan, cmpute, StudyingFather, Enter-tainer, Xeonacid, aofall, H-J-Granger, mgt, countercurrent-time, NachtgeistW, Ir1d, Marcythm, sshwy, Tiphereth-A, AngelKitty, CCXXXI, cjsoft, diauweb, Early0v0, ezoixx130, GekkaSaori, Konano, LovelyBuggies, Makkiy, minghu6, P-Y-Y, PotassiumWings, SamZhangQingChuan, Suyun514, weiyong1024, billchenchina, c-forrest, GavinZhengOI, Gesrua, greyqz, hhc0001, kxccc, leonfyr, Link-cute, lychees, Ocautator, Peanut-Tang, Shen-Linwood, shuzhouliu, SukkaW, TOMWT-qwq, yusancky 本页面的全部内容在CC BY-SA 4.0SATA 协议之条款下提供,附加条款亦可能应用