算术运算符
返回特定算术运算的结果。
运算符名 | 语法 | 原型示例(对于 class T) | ||
---|---|---|---|---|
类内定义 | 类外定义 | |||
一元加 | +a | T T::operator+() const; | T operator+(const T &a); | |
一元减 | -a | T T::operator-() const; | T operator-(const T &a); | |
加法 | a + b | T T::operator+(const T2 &b) const; | T operator+(const T &a, const T2 &b); | |
减法 | a - b | T T::operator-(const T2 &b) const; | T operator-(const T &a, const T2 &b); | |
乘法 | a * b | T T::operator*(const T2 &b) const; | T operator*(const T &a, const T2 &b); | |
除法 | a / b | T T::operator/(const T2 &b) const; | T operator/(const T &a, const T2 &b); | |
模 | a % b | T T::operator%(const T2 &b) const; | T operator%(const T &a, const T2 &b); | |
逐位非 | ~a | T T::operator~() const; | T operator~(const T &a); | |
逐位与 | a & b | T T::operator&(const T2 &b) const; | T operator&(const T &a, const T2 &b); | |
逐位或 | a | b | T T::operator|(const T2 &b) const; | T operator|(const T &a, const T2 &b); | |
逐位异或 | a ^ b | T T::operator^(const T2 &b) const; | T operator^(const T &a, const T2 &b); | |
逐位左移 | a << b | T T::operator<<(const T2 &b) const; | T operator<<(const T &a, const T2 &b); | |
逐位右移 | a >> b | T T::operator>>(const T2 &b) const; | T operator>>(const T &a, const T2 &b); | |
|
通用解释
所有内建算术运算符计算特定算术运算的结果,并返回它的结果。不修改实参。
转换
如果传递给内建算术运算符的操作数是整数或无作用域枚举类型,那么在所有其他操作前(但在左值到右值转换后,如果适用)会对操作数实施整数提升。如果操作数之一具有数组或函数类型,那么实施数组到指针和函数到指针转换。
对于(除移位之外的)二元运算符,当提升后的操作数拥有不同类型时,实施一般算术转换。
溢出
无符号整数算术始终进行 modulo 2n
运算,其中 n 是该整数的位数。例如对于 unsigned int,向 UINT_MAX 加一得到 0,而从 0 减一得到 UINT_MAX。
有符号整数算术运算溢出(结果类型无法容纳它的结果)时,行为未定义,此类操作可能会表现为:
- 按照表示法的规则(典型为补码)发生回绕,
- 在某些平台上或由于编译器选项(例如 GCC 和 Clang 中的
-ftrapv
)引发陷阱, - 在某些时候饱和到最小或最大值(在许多 DSP 上),
- 完全被编译器优化掉。
浮点环境
如果支持
#pragma STDC FENV_ACCESS 并设置它为 ON
,那么所有浮点算术运算符都服从当前浮点舍入方向,并报告 math_errhandling 中指定的浮点算术错误,除非其在静态初始化器中发生(此时不引发浮点异常,且舍入模式是最近舍入)。
浮点缩略
除非支持
#pragma STDC FP_CONTRACT 并设置它为 OFF
,否则所有浮点算术都可以如同它的中间结果拥有无限范围和精度一般进行,即允许实施省略舍入误差和浮点异常的优化。例如 C++ 允许以单条融合乘加 CPU 指令来实现 (x * y) + z,或把 a = x * x * x * x; 优化为 tmp = x * x; a = tmp * tmp。
无关乎缩略,浮点算术的中间结果可拥有与它的类型所指定不同的范围和精度,见 FLT_EVAL_METHOD。
正式来讲,C++ 标准不在浮点运算的精度上做任何保证。
一元算术运算符
一元算术运算符表达式的形式为
+ 表达式
|
(1) | ||||||||
- 表达式
|
(2) | ||||||||
一元 +
和 -
运算符的优先级高于所有二元算术运算符,所以表达式 无法包含位于顶层的二元算术运算符。这些运算符从右到左关联:
+a - b; // 等价于 (+a) - b,而不是 +(a - b) -c + d; // 等价于 (-c) + d,而不是 -(c + d) +-e; // 等价于 +(-e),在 e 是内建类型的情况下一元 + 是无操作, // 因为任何提升操作都已经在取反过程中进行
内建一元算术运算符
-a,其中 N 是提升后的位数。
- 也就是说,结果是操作数的补码(其中操作数和结果都视为无符号数)。
重载
在针对用户定义运算符的重载决议中,对于每个无 cv 限定的提升后算术类型 A
和每个类型 T
,下列函数签名参与重载决议:
A operator+(A) |
||
T* operator+(T*) |
||
A operator-(A) |
||
#include <iostream> int main() { char c = 0x6a; int n1 = 1; unsigned char n2 = 1; unsigned int n3 = 1; std::cout << "char:" << c << " int:" << +c << '\n' << "-1,当 1 的类型是 signed 时:" << -n1 << '\n' << "-1,当 1 的类型是 unsigned char 时:" << -n2 << '\n' << "-1,当 1 的类型是 unsigned int 时:" << -n3 << '\n'; char a[3]; std::cout << "数组大小:" << sizeof a << '\n' << "指针大小:" << sizeof +a << '\n'; }
输出:
char:j int:106 -1,当 1 的类型是 signed 时:-1 -1,当 1 的类型是 unsigned char 时:-1 -1,当 1 的类型是 unsigned int 时:4294967295 数组大小:3 指针大小:8
加性运算符
二元加性运算符表达式的形式为
左操作数 + 右操作数
|
(1) | ||||||||
左操作数 - 右操作数
|
(2) | ||||||||
二元 +
和 -
运算符的优先级高于 *
、/
和 %
以外的所有其他二元算术运算符。这些运算符从左到右结合:
a + b * c; // 等价于 a + (b * c) ,而不是 (a + b) * c d / e - f; // 等价于 (d / e) - f ,而不是 d / (e - f) g + h >> i; // 等价于 (g + h) >> i,而不是 g + (h >> i) j - k + l - m; // 等价于 ((j - k) + l) - m
内建加性运算符
对于内建二元加和二元减运算符,左操作数 和右操作数 都必须是纯右值,并且必须满足以下条件之一:
- 两个操作数都具有算术或无作用域枚举类型。此时会对它们进行一般算术转换。
- 恰有一个操作数具有整数或无作用域枚举类型。此时会对该操作数进行整数提升。
在本段的后续描述中,“操作数”、左操作数 和右操作数 均指代转换后或提升后的操作数。
- 两个操作数都具有算术类型。此时结果是两个操作数的和。
- 一个操作数是指向完全定义的对象类型的指针,而另一个操作数具有整数类型。此时会从该指针加上该整数值(见指针算术)。
如果两个操作数都具有浮点类型,并且该类型支持 IEEE 浮点算术(见 std::numeric_limits::is_iec559),那么会有以下特殊计算结果:
- 如果操作数之一是 NaN,那么结果是 NaN。
- 无穷减无穷是 NaN,并引发 FE_INVALID。
- 无穷加负无穷是 NaN,并引发 FE_INVALID。
指针算术
当从具有指针类型的表达式 P 加上或减去具有整数类型的表达式 J 时,结果的类型与 P 相同。
- 如果 P 求值为空指针值且 J 求值为 0,那么结果是空指针值。
- 否则,如果 P 指向包含 n 个元素的数组对象 x 的第
i
个元素,那么给定 J 的值为 j,按以下方式从 P 加上或减去值:
- 表达式 P + J 和 J + P
- 在 i + j 在
[
0,
n)
中时指向 x 的第i+j
个元素,并且 - 在 i + j 是 n 时是 x 的最后一个元素的尾后指针。
- 在 i + j 在
- 表达式 P - J
- 在 i - j 在
[
0,
n)
中时指向 x 的第i-j
个元素,并且 - 在 i - j 是 n 时是 x 的最后一个元素的尾后指针。
- 在 i - j 在
- 其他 j 值都会导致未定义行为。
- 否则,如果 P 指向完整对象,基类子对象或成员子对象 y,那么给定 J 的值为 j,按以下方式从 P 加上或减去值:
- 表达式 P + J 和 J + P
- 在 j 是 0 时指向 y,并且
- 在 j 是 1 时是 y 的尾后指针。
- 表达式 P - J
- 在 j 是 0 时指向 y,并且
- 在 j 是 -1 时是 y 的尾后指针。
- 其他 j 值都会导致未定义行为。
- 否则,如果 P 是对象 z 的尾后指针,那么给定 J 的值为 j:
- 如果 z 是指向包含 n 个元素的数组对象,那么按以下方式从 P 加上或减去值:
- 表达式 P + J 和 J + P
- 在 n + j 在
[
0,
n)
中时指向 z 的第n+j
个元素,并且 - 在 j 是 0 时是 z 的最后一个元素的尾后指针。
- 在 n + j 在
- 表达式 P - J
- 在 n - j 在
[
0,
n)
中时指向 z 的第n-j
个元素,并且 - 在 j 是 0 时是 z 的最后一个元素的尾后指针。
- 在 n - j 在
- 其他 j 值都会导致未定义行为。
- 否则,按以下方式从 P 加上或减去值:
- 表达式 P + J 和 J + P
- 在 j 是 -1 时指向 z,并且
- 在 j 是 0 时是 z 的尾后指针。
- 表达式 P - J
- 在 j 是 1 时指向 z,并且
- 在 j 是 0 时是 z 的尾后指针。
- 其他 j 值都会导致未定义行为。
- 否则行为未定义。
当两个指针表达式 P 和 Q 相减时,结果类型是 std::ptrdiff_t。
- 如果 P 和 Q 都求值为空指针值,那么结果是 0。
- 否则,如果 P 和 Q 分别指向相同的数组对象 x 的第
i
个和第j
个元素,那么表达式 P - Q 的值是 i − j。
- 如果 i − j 无法以 std::ptrdiff_t 表示,那么行为未定义。
- 否则,如果 P 和 Q 指向相同的完整对象,基类子对象或成员子对象,那么结果是 0。
- 否则行为未定义。
这些指针算术运算符使得指针满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。
对于加法和减法,如果 P 或 Q 的类型是“指向(可有 cv 限定的)T
的指针”,并且 T
和数组元素类型不相似,那么行为未定义:
int arr[5] = {1, 2, 3, 4, 5}; unsigned int *p = reinterpret_cast<unsigned int*>(arr + 1); unsigned int k = *p; // OK:k 的值是 2 unsigned int *q = p + 1; // 未定义行为:p 指向的是 int,而不是 unsigned int
重载
在针对用户定义运算符的重载决议中,对于每对提升后的算术类型 L
和 R
和每个对象类型 T
,下列函数签名参与重载决议:
LR operator+(L, R) |
||
LR operator-(L, R) |
||
T* operator+(T*, std::ptrdiff_t) |
||
T* operator+(std::ptrdiff_t, T*) |
||
T* operator-(T*, std::ptrdiff_t) |
||
std::ptrdiff_t operator-(T*, T*) |
||
其中 LR
是对 L
和 R
实施一般算术转换的结果。
#include <iostream> int main() { char c = 2; unsigned int un = 2; int n = -10; std::cout << " 2 + (-10),当 2 的类型是 char 时 = " << c + n << '\n' << " 2 + (-10),当 2 的类型是 unsigned 时 = " << un + n << '\n' << " -10 - 2.12 = " << n - 2.12 << '\n'; char a[4] = {'a', 'b', 'c', 'd'}; char* p = &a[1]; std::cout << "指针相加的例子:" << *p << *(p + 2) << *(2 + p) << *(p - 1) << '\n'; char* p2 = &a[4]; std::cout << "指针的差:" << p2 - p << '\n'; }
输出:
2 + (-10),当 2 的类型是 char 时 = -8 2 + (-10),当 2 的类型是 unsigned 时 = 4294967288 -10 - 2.12 = -12.12 指针相加的例子:bdda 指针的差:3
乘性运算符
乘性运算符表达式的形式为
左操作数 * 右操作数
|
(1) | ||||||||
左操作数 / 右操作数
|
(2) | ||||||||
左操作数 % 右操作数
|
(3) | ||||||||
乘性运算符的优先级高于所有其他二元算术运算符。这些运算符从左到右结合:
a + b * c; // 等价于 a + (b * c) ,而不是 (a + b) * c d / e - f; // 等价于 (d / e) - f ,而不是 d / (e - f) g % h >> i; // 等价于 (g % h) >> i,而不是 g % (h >> i) j * k / l % m; // 等价于 ((j * k) / l) % m
内建乘性运算符
对于内建的乘法和除法运算符,两个操作数都必须具有算术或无作用域枚举类型。对于内建的取余运算符,两个操作数都必须具有整数或无作用域枚举类型。对两个操作数应用一般算术转换。
在本段的后续描述中,“操作数”、左操作数 和右操作数 均指代转换后的操作数。
- 如果操作数之一是 NaN,那么结果是 NaN。
- 无穷乘以零是 NaN,并引发 FE_INVALID。
- 如果操作数之一是 NaN,那么结果是 NaN。
- 非零数除以 ±0.0 会得到符号正确的无穷,并引发 FE_DIVBYZERO。
- 0.0 除以 0.0 是 NaN,并引发 FE_INVALID。
注意:在 CWG 问题 614 解决(N2757)之前,如果二元运算符 % 的一或两个操作数为负,那么余数符由实现定义,因为它取决于整数除法的舍入方向。函数 std::div 在该情况下提供良好定义的行为。
注意:对于浮点余数,见 std::remainder 和 std::fmod。
重载
在针对用户定义运算符的重载决议中,对于每对提升后的算术类型 LA
与 RA
及每对提升后的整数类型 LI
与 RI
,下列函数签名参与重载决议:
LRA operator*(LA, RA) |
||
LRA operator/(LA, RA) |
||
LRI operator%(LI, RI) |
||
其中 LRx
是对 Lx
和 Rx
实施一般算术转换的结果。
#include <iostream> int main() { char c = 2; unsigned int un = 2; int n = -10; std::cout << "2 * (-10),当 2 的类型是 char 时 = " << c * n << '\n' << "2 * (-10),当 2 的类型是 unsigned 时 = " << un * n << '\n' << "-10 / 2.12 = " << n / 2.12 << '\n' << "-10 / 21 = " << n / 21 << '\n' << "-10 % 21 = " << n % 21 << '\n'; }
输出:
2 * (-10),当 2 的类型是 char 时 = -20 2 * (-10),当 2 的类型是 unsigned 时 = 4294967276 -10 / 2.12 = -4.71698 -10 / 21 = 0 -10 % 21 = -10
逐位逻辑运算符
逐位逻辑运算符表达式的形式为
~ 右操作数
|
(1) | ||||||||
左操作数 & 右操作数
|
(2) | ||||||||
左操作数 | 右操作数
|
(3) | ||||||||
左操作数 ^ 右操作数
|
(4) | ||||||||
逐位非运算符的优先级高于所有二元算术运算符。它从右到左结合:
~a - b; // 等价于 (~a) - b,而不是 ~(a - b) ~c * d; // 等价于 (~c) * d,而不是 ~(c * d) ~-e; // 等价于 ~(-e)
~ 在后随类型名或 decltype
说明符 (C++11 起)时在语法上有歧义:它可以是 operator~,也可以是析构函数标识符的开始。该歧义通过将 ~ 视为 operator~ 解决。只有在不能组成 operator~ 的地方才能用 ~ 作为析构函数标识符的开始。
所有其他逐位逻辑运算符的优先级低于所有其他二元算术运算符。此外,逐位与的优先级高于逐位异或,逐位异或的优先级高于逐位或。这些运算符从左到右结合:
a & b * c; // 等价于 a & (b * c) ,而不是 (a & b) * c d / e ^ f; // 等价于 (d / e) ^ f ,而不是 d / (e ^ f) g << h | i; // 等价于 (g << h) | i,而不是 g << (h | i) j & k & l; // 等价于 (j & k) & l m | n ^ o // 等价于 m | (n ^ o)
内建逐位逻辑运算符
对于内建的逐位非运算符,右操作数 必须是整数或无作用域枚举类型的纯右值,并且会对它进行整数提升。对于其他内建的逐位逻辑运算符,两个操作数都必须具有整数或无作用域枚举类型,并且会对它们进行一般算术转换。
在本段的后续描述中,“操作数”、左操作数 和右操作数 均指代转换后或提升后的操作数。
- 也就是说,结果是操作数的反码(其中操作数和结果都视为无符号数)。
重载
在针对用户定义运算符的重载决议中,对于每对提升后的整数类型 L
和 R
,下列函数签名参与重载决议:
R operator~(R) |
||
LR operator&(L, R) |
||
LR operator^(L, R) |
||
LR operator|(L, R) |
||
其中 LR
是对 L
和 R
实施一般算术转换的结果。
#include <bitset> #include <cstdint> #include <iomanip> #include <iostream> int main() { uint16_t mask = 0x00f0; uint32_t x0 = 0x12345678; uint32_t x1 = x0 | mask; uint32_t x2 = x0 & ~mask; uint32_t x3 = x0 & mask; uint32_t x4 = x0 ^ mask; uint32_t x5 = ~x0; using bin16 = std::bitset<16>; using bin32 = std::bitset<32>; std::cout << std::hex << std::showbase << "掩码:" << mask << std::setw(39) << bin16(mask) << '\n' << "值:" << x0 << std::setw(33) << bin32(x0) << '\n' << "设置各位:" << x1 << std::setw(33) << bin32(x1) << '\n' << "清除各位:" << x2 << std::setw(33) << bin32(x2) << '\n' << "选择各位:" << x3 << std::setw(39) << bin32(x3) << '\n' << "异或各位:" << x4 << std::setw(33) << bin32(x4) << '\n' << "取反各位:" << x5 << std::setw(33) << bin32(x5) << '\n'; }
输出:
掩码:0xf0 0000000011110000 值:0x12345678 00010010001101000101011001111000 设置各位:0x123456f8 00010010001101000101011011111000 清除各位:0x12345608 00010010001101000101011000001000 选择各位:0x70 00000000000000000000000001110000 异或各位:0x12345688 00010010001101000101011010001000 取反各位:0xedcba987 11101101110010111010100110000111
移位运算符
移位运算符表达式的形式为
左操作数 << 右操作数
|
(1) | ||||||||
左操作数 >> 右操作数
|
(2) | ||||||||
移位运算符的优先级高于逐位逻辑运算符,但低于加性和乘性运算符。这些运算符从左到右结合:
a >> b * c; // 等价于 a >> (b * c) ,而不是 (a >> b) * c d << e & f; // 等价于 (d << e) & f ,而不是 d << (e & f) g << h >> i; // 等价于 (g << h) >> i,而不是 g << (h >> i)
内建移位运算符
对于内建的移位运算符,两个操作数都必须具有整数或无作用域枚举类型,并且会对它们进行整数提升。
在本段的后续描述中,“操作数”、a、b、左操作数 和右操作数 均指代提升后的操作数。
任何情况下,如果右操作数 的值为负或不小于左操作数 中的位数,那么行为未定义。
对于无符号 a,a << b 的值是 a * 2b 对于有符号的非负 a,如果 a * 2b 对于负 a,a << b 的行为未定义。 对于无符号 a 和有符号的非负 a,a >> b 的值是 a/2b 对于负 a,a >> b 的值由实现定义(大多数平台上进行算术右移,因此结果保留为负)。 |
(C++20 前) |
a << b 的值是与 a * 2b a >> b 的值是 a/2b |
(C++20 起) |
返回类型是左操作数 的类型。
重载
在针对用户定义运算符的重载决议中,对于每对提升后的整数类型 L
和 R
,下列函数签名参与重载决议:
L operator<<(L, R) |
||
L operator>>(L, R) |
||
#include <iostream> enum { ONE = 1, TWO = 2 }; int main() { std::cout << std::hex << std::showbase; char c = 0x10; unsigned long long ull = 0x123; std::cout << "0x123 << 1 = " << (ull << 1) << '\n' << "0x123 << 63 = " << (ull << 63) << '\n' // 无符号中的溢出 << "0x10 << 10 = " << (c << 10) << '\n'; // 提升 char 到 int long long ll = -1000; std::cout << std::dec << "-1000 >> 1 = " << (ll >> ONE) << '\n'; }
输出:
0x123 << 1 = 0x246 0x123 << 63 = 0x8000000000000000 0x10 << 10 = 0x4000 -1000 >> 1 = -500
标准库
许多标准库类型都重载了算术运算符。
一元算术运算符
实现一元 + 和一元 - ( std::chrono::duration<Rep,Period> 的公开成员函数) | |
对复数运用一元运算符 (函数模板) | |
对 valarray 的每个元素运用一元算术运算符 ( std::valarray<T> 的公开成员函数) |
加性运算符
(C++11) |
实施涉及时间点的加法和减法运算 (函数模板) |
实现以时长为实参的算术运算 (函数模板) | |
(C++20) |
将 year_month_day 与一定量的年数或月数相加或相减 (函数) |
连接两个字符串,一个字符串和一个 char,或者一个字符串和一个 string_view (函数模板) | |
推进或减小迭代器 ( std::reverse_iterator<Iter> 的公开成员函数)
| |
推进或减小迭代器 ( std::move_iterator<Iter> 的公开成员函数)
| |
在两个复数,或一个复数与一个标量上进行复数算术运算 (函数模板) | |
对两个 valarray 的每个元素,或一个 valarray 的每个元素和一个值运用二元运算符 (函数模板) |
乘性运算符
实现以时长为实参的算术运算 (函数模板) | |
在两个复数,或一个复数与一个标量上进行复数算术运算 (函数模板) | |
对两个 valarray 的每个元素,或一个 valarray 的每个元素和一个值运用二元运算符 (函数模板) |
逐位逻辑运算符
进行二进制与、或、异或及非 ( std::bitset<N> 的公开成员函数) | |
在位集上执行二元逻辑操作 (函数) | |
对 valarray 的每个元素运用一元算术运算符 ( std::valarray<T> 的公开成员函数)
| |
对两个 valarray 的每个元素,或一个 valarray 的每个元素和一个值运用二元运算符 (函数模板) |
移位运算符
对两个 valarray 的每个元素,或一个 valarray 的每个元素和一个值运用二元运算符 (函数模板) | |
进行二进制左移和右移 ( std::bitset<N> 的公开成员函数)
|
流插入/提取运算符
整个标准库中,移位运算符常对输入/输出流(std::ios_base& 或从它派生的类之一)重载,以之为左运算数和返回类型。这种运算符被称为流插入和流提取运算符:
提取带格式数据 ( std::basic_istream<CharT,Traits> 的公开成员函数) | |
提取字符和字符数组 (函数模板) | |
插入带格式数据 ( std::basic_ostream<CharT,Traits> 的公开成员函数) | |
插入字符数据,或向右值流插入 (函数) | |
复数的序列化和反序列化 (函数模板) | |
执行位集的流输入和输出 (函数) | |
执行字符串的流输入与输出 (函数模板) | |
(C++11) |
执行伪随机数引擎的流输入和输出 (函数模板) |
(C++11) |
执行伪随机数分布的流输入和输出 (函数模板) |
缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
缺陷报告 | 应用于 | 出版时的行为 | 正确行为 |
---|---|---|---|
CWG 614 | C++98 | 整数除法的算术商的取整方向由实现定义 | 向零取整(舍弃小数部分) |
CWG 1450 | C++98 | 未指明 a / b 在无法以结果类型表示时的结果 | 此时 a / b 和 a % b 的行为均未定义 |
CWG 1457 | C++98 | 将正的有符号值的最左端的 1 位移入符号位的行为未定义 | 赋予良好定义 |
CWG 1504 | C++98 | 指向数组元素的基类子对象的指针可以用于指针算术 | 此时行为未定义 |
CWG 1515 | C++98 | 只有声明了 unsigned 的无符号整数需要遵循 modulo 2n 算术规则 |
应用到所有无符号整数 |
CWG 1642 | C++98 | 算术运算符的操作数可以是左值 | 部分操作数必须是右值 |
CWG 1865 | C++98 | CWG 问题 1504 的解决方案导致指向数组元素的指针在指针指向 类型和数组类型的非顶层 cv 限定不同时参与指针运算的行为未定义 |
赋予良好定义 |
CWG 1971 | C++98 | 不明确用来解决 ~ 的歧义的规则是否适用 ~X(0) 这种情况 | 适用这种情况 |
CWG 2419 | C++98 | 只有通过 & 获取的到非数组对象的指针才会在 指针运算中被视为到大小为 1 的数组的首元素的指针 |
应用到所有到非数组对象的指针 |
CWG 2626 | C++98 | 内建 operator~ 的结果只是“反码”,而没有适当的定义 | 结果用二进制表示进行描述 |
CWG 2724 | C++20 | 向右移位的取整方向不明确 | 使之明确 |
CWG 2853 | C++98 | 对象末尾后指针无法与整数相加或相减 | 可以相加或相减 |
参阅
常见运算符 | ||||||
---|---|---|---|---|---|---|
赋值 | 自增/自减 | 算术 | 逻辑 | 比较 | 成员访问 | 其他 |
a = b |
++a |
+a |
!a |
a == b |
a[b] |
函数调用 |
a(...) | ||||||
逗号 | ||||||
a, b | ||||||
条件 | ||||||
a ? b : c | ||||||
特殊运算符 | ||||||
static_cast 转换一个类型为另一相关类型 |