Namespaces
Variants

Arithmetic operators

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

返回特定算术运算的结果。

运算符名称 语法 原型示例(针对 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 ) ;
备注
  • 本表中所有运算符均可 重载
  • 所有内置运算符均返回值,大多数 用户定义重载 也返回值,以便用户定义运算符能以与内置运算符相同的方式使用。但在用户定义运算符重载中,可使用任何类型作为返回类型(包括 void )。特别地, operator << operator >> 的流插入与流提取重载返回 T&
  • T2 可为任意类型(包括 T )。

目录

通用说明

所有内置算术运算符均计算特定算术运算的结果并返回其值。参数不会被修改。

转换

如果传递给内置算术运算符的操作数是整型或无作用域枚举类型,那么在执行任何其他操作之前(但在适用的情况下进行左值到右值转换后),该操作数将进行 整型提升 。如果操作数具有数组或函数类型,则会应用 数组到指针 函数到指针 的转换。

对于二元运算符(移位运算符除外),如果提升后的操作数具有不同类型,则应用 常用算术转换 规则。

溢出

无符号整数运算始终以 2 n
为模执行,其中 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)
1) 一元加号(类型提升)。
2) 一元减号(取负)。

一元运算符 + - 具有比所有二元算术运算符更高的 优先级 ,因此 表达式 不能包含顶层的二元算术运算符。这些运算符采用从右向左的结合性:

+a - b; // 等价于 (+a) - b,而非 +(a - b)
-c + d; // 等价于 (-c) + d,而非 -(c + d)
+-e; // 等价于 +(-e),若“e”为内置类型则一元+是空操作
     // 因为所有可能的提升已在取负操作期间完成

内置一元算术运算符

1) 对于内置一元加运算符, expression 必须是算术类型、无作用域枚举类型或指针类型的纯右值。若 expression 具有整型或无作用域枚举类型,则对其执行整型提升。结果的类型是 expression (可能提升后)的类型。
内置提升的结果是 表达式 的值。当操作数是提升后的整型或指针类型的纯右值时,内置一元运算是空操作。否则,将通过整型提升、左值到右值转换、数组到指针转换、函数到指针转换或用户定义转换来改变操作数的类型或值类别。例如,在单目加表达式中 char 会被转换为 int ,非泛型无捕获的 lambda表达式 会被转换为函数指针 (C++11 起)
2) 对于内置一元减运算符, expression 必须是算术类型或无作用域枚举类型的纯右值。对 expression 执行整型提升。结果的类型是 expression 提升后的类型。
内置取反运算的结果是提升后 表达式 的负值。对于无符号类型 a - a 的值为 2 N
-a
,其中 N 表示提升后的位宽。
  • 换言之,该运算结果是操作数的二进制补码(操作数与结果均视为无符号数)。

重载

针对用户定义运算符的重载决议 中,对于每个无cv限定符的提升算术类型 A 和每个类型 T ,以下函数签名会参与重载决议:

A operator + ( A )
T * operator + ( T * )
A operator - ( A )
(注:根据要求,所有HTML标签、属性及 标签内的C++代码均未翻译,仅对页面说明性文字进行了简体中文翻译。由于原始网页内容中除代码外无其他可翻译文本,故输出保持原样)
#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, where 1 is signed: " << -n1 << "\n"
                 "-1, where 1 is unsigned char: " << -n2 << "\n"
                 "-1, where 1 is unsigned int: " << -n3 << '\n';
    char a[3];
    std::cout << "size of array: " << sizeof a << "\n"
                 "size of pointer: " << sizeof +a << '\n';
}

可能的输出:

char: j int: 106
-1, where 1 is signed: -1
-1, where 1 is unsigned char: -1
-1, where 1 is unsigned int: 4294967295
size of array: 3
size of pointer: 8

加法运算符

加法运算符表达式具有以下形式

lhs + rhs (1)
lhs - rhs (2)
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

内置加法运算符

对于内置二元加法和二元减法运算符, lhs rhs 都必须是纯右值,且必须满足以下条件之一:

  • 两个操作数都具有算术类型或无作用域枚举类型。此时,对两个操作数执行 常规算术转换
  • 仅有一个操作数具有整数类型或无作用域枚举类型。此时,对该操作数应用整数提升。

在本节剩余描述中,"操作数"、 lhs rhs 均指经过转换或提升后的操作数。

1) 对于内置加法运算,必须满足以下条件之一:
  • 两个操作数均具有算术类型。此时结果为操作数之和。
  • 一个操作数是指向完整定义对象类型的指针,另一个操作数具有整型类型。此时整型值会与指针相加(参见 指针算术 )。
2) 对于内置减法运算,必须满足以下条件之一:
  • 两个操作数都具有算术类型。此时结果为从 lhs 中减去 rhs 得到的差值。
  • lhs 为指向完全定义对象类型的指针,且 rhs 具有整数类型。此时从指针中减去该整数值(参见 指针算术 )。
  • 两个操作数均为指向同一完全定义对象类型的 cv 限定或非限定版本的指针。此时从 lhs 中减去 rhs (参见 指针算术 )。

如果两个操作数都具有浮点类型,且该类型支持 IEEE 浮点算术(参见 std::numeric_limits::is_iec559 ):

  • 若任一操作数为 NaN,则结果为 NaN。
  • 无穷大减无穷大为 NaN,并引发 FE_INVALID
  • 正无穷大加负无穷大为 NaN,并引发 FE_INVALID

指针算术

当一个具有整数类型的表达式 J 与一个指针类型的表达式 P 相加或相减时,结果的类型与 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 最后一个元素之后的位置
  • 表达式 P - J
  • i - j [ 0 , n ) 范围内时,指向 x 的第 i-j 个元素
  • i - j 等于 n 时,指向 x 最后一个元素之后的位置
  • 其他 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 最后一个元素之后的位置。
  • 表达式 P - J
  • n - j 处于区间 [ 0 , n ) 时,指向 z 的第 n-j 个元素;
  • j 0 时,指向 z 最后一个元素之后的位置。
  • 其他 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
  • 否则,若 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; // 正确:变量“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 * )
说明:由于所有内容均位于 ` ` 标签内(属于代码标签),且包含C++专业术语,根据要求未进行任何翻译处理。表格结构和HTML标签完全保留原样。

其中 LR 是对 L R 进行 常规算术转换 的结果。

#include <iostream>
int main()
{
    char c = 2;
    unsigned int un = 2;
    int n = -10;
    std::cout << " 2 + (-10), where 2 is a char    = " << c + n << "\n"
                 " 2 + (-10), where 2 is unsigned  = " << un + n << "\n"
                 " -10 - 2.12  = " << n - 2.12 << '\n';
    char a[4] = {'a', 'b', 'c', 'd'};
    char* p = &a[1];
    std::cout << "Pointer addition examples: " << *p << *(p + 2)
              << *(2 + p) << *(p - 1) << '\n';
    char* p2 = &a[4];
    std::cout << "Pointer difference: " << p2 - p << '\n';
}

输出:

 2 + (-10), where 2 is a char    = -8
 2 + (-10), where 2 is unsigned  = 4294967288
 -10 - 2.12  = -12.12
Pointer addition examples: bdda
Pointer difference: 3

乘法运算符

乘法运算符表达式具有以下形式

lhs * rhs (1)
lhs / rhs (2)
lhs % rhs (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

内置乘法运算符

对于内置乘法和除法运算符,两个操作数必须具有算术类型或无作用域枚举类型。对于内置取余运算符,两个操作数必须具有整数类型或无作用域枚举类型。 常规算术转换 会在两个操作数上执行。

在本节剩余描述中,"操作数"、 lhs rhs 均指转换后的操作数。

1) 内置乘法的运算结果是操作数的乘积。
若两个操作数均为浮点类型,且该类型支持 IEEE 浮点算术(参见 std::numeric_limits::is_iec559 ):
  • NaN 与任意数字相乘均得到 NaN。
  • 无穷大与零相乘得到 NaN 并引发 FE_INVALID
2) 内置除法运算的结果是 lhs 除以 rhs 。若 rhs 为零,则行为未定义。
若两个操作数均为整数类型,结果为代数商(执行整数除法):商向零截断(小数部分被舍弃)。
若两个操作数均为浮点类型,且该类型支持 IEEE 浮点算术(参见 std::numeric_limits::is_iec559 ):
  • 若任一操作数为 NaN,结果为 NaN。
  • 非零数除以 ±0.0 将得到正确符号的无穷大,并触发 FE_DIVBYZERO
  • 0.0 除以 0.0 将得到 NaN,并触发 FE_INVALID
3) 内置取余运算的结果是 lhs 除以 rhs 的整数除法余数。若 rhs 为零,则行为未定义。
如果 a / b 在结果类型中可表示,则 ( a / b ) * b + a % b == a
如果 a / b 在结果类型中无法表示,则 a / b a % b 的行为均为未定义(这意味着在二进制补码系统中 INT_MIN % - 1 是未定义的)。

注意:在 CWG issue 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), where 2 is a char    = " << c * n << "\n"
                 "2 * (-10), where 2 is unsigned  = " << un * n << "\n"
                 "-10 / 2.12  = " << n / 2.12 << "\n"
                 "-10 / 21  = " << n / 21 << "\n"
                 "-10 % 21  = " << n % 21 << '\n';
}

输出:

2 * (-10), where 2 is a char    = -20
2 * (-10), where 2 is unsigned  = 4294967276
-10 / 2.12  = -4.71698
-10 / 21  = 0
-10 % 21  = -10

位逻辑运算符

位逻辑运算符表达式的形式为

~ rhs (1)
lhs & rhs (2)
lhs | rhs (3)
lhs ^ rhs (4)
1) 按位取反。
2) 按位与。
3) 按位或。
4) 按位异或。

位非运算符的 优先级 高于所有二元算术运算符。其结合性为从右至左:

~a - b; // 等价于 (~a) - b,而非 ~(a - b)
~c * d; // 等价于 (~c) * d,而非 ~(c * d)
~-e; // 等价于 ~(-e)

~ 后接 类型名称 decltype 说明符 (C++11 起) 时,语法存在歧义:它既可能表示运算符~,也可能是 析构函数 标识符的开头)。该歧义通过将 ~ 视为运算符~来解决。 ~ 仅在构成运算符~在语法上无效的位置才能作为析构函数标识符的开头。

所有其他位逻辑运算符的 优先级 均低于其他所有二元算术运算符。位与运算符的优先级高于位异或运算符,而位异或运算符的优先级又高于位或运算符。这些运算符均具有从左到右的结合性:

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)

内置位运算逻辑运算符

对于内置的按位取反运算符, rhs 必须是整数类型或无作用域枚举类型的纯右值,并对 rhs 执行整数提升。对于其他内置的按位逻辑运算符,两个操作数都必须具有整数类型或无作用域枚举类型,并对两个操作数执行 常规算术转换

在本节剩余描述中,"操作数"、 lhs rhs 均指经过转换或提升后的操作数。

1) 给定操作数为 x ,内置按位取反操作的结果为 r 。对于 x 的二进制表示中的每个系数 x_i ,其对应的 r 的二进制表示系数 r_i 1 (当 x_i 0 时),否则为 0
  • 换言之,该结果是操作数的反码(操作数与结果均视为无符号数)。
结果 r 的类型与操作数 x 的类型相同。
2-4) 给定操作数分别为 x y ,内置二元位逻辑运算的结果为 r 。对于 x y 的二进制表示中的每对系数 x_i y_i ,其对应的 r 的二进制表示中的系数 r_i
2) 1 当且仅当 x_i y_i 均为 1 时成立,否则为 0
3) 1 当至少一个 x_i y_i 1 时成立,否则为 0
4) 1 当且仅当 x_i y_i 中有且仅有一个为 1 ,否则为 0
结果 r 的类型与操作数 x y 的类型相同。

重载

针对用户定义运算符的重载决议 中,对于每对提升后的整数类型 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()
{
    std::uint16_t mask = 0x00f0;
    std::uint32_t x0 = 0x12345678;
    std::uint32_t x1 = x0 | mask;
    std::uint32_t x2 = x0 & ~mask;
    std::uint32_t x3 = x0 & mask;
    std::uint32_t x4 = x0 ^ mask;
    std::uint32_t x5 = ~x0;
    using bin16 = std::bitset<16>;
    using bin32 = std::bitset<32>;
    std::cout << std::hex << std::showbase
              << "Mask: " << mask << std::setw(49) << bin16(mask) << "\n"
                 "Value: " << x0 << std::setw(42) << bin32(x0) << "\n"
                 "Setting bits: " << x1 << std::setw(35) << bin32(x1) << "\n"
                 "Clearing bits: " << x2 << std::setw(34) << bin32(x2) << "\n"
                 "Selecting bits: " << x3 << std::setw(39) << bin32(x3) << "\n"
                 "XOR-ing bits: " << x4 << std::setw(35) << bin32(x4) << "\n"
                 "Inverting bits: " << x5 << std::setw(33) << bin32(x5) << '\n';
}

输出:

Mask: 0xf0                                 0000000011110000
Value: 0x12345678          00010010001101000101011001111000
Setting bits: 0x123456f8   00010010001101000101011011111000
Clearing bits: 0x12345608  00010010001101000101011000001000
Selecting bits: 0x70       00000000000000000000000001110000
XOR-ing bits: 0x12345688   00010010001101000101011010001000
Inverting bits: 0xedcba987 11101101110010111010100110000111

位运算符

按位移位运算符表达式的形式为

lhs << rhs (1)
lhs >> rhs (2)
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 ”、“ lhs ”和“ rhs ”均指经过转换或提升后的操作数。

如果 rhs 的值为负数或不小于 lhs 的位数,则行为未定义。

对于无符号类型 a a << b 的值为 a * 2 b
2 N
取模的结果,其中 N 是返回类型的位数(即执行按位左移,且移出目标类型的位被丢弃)。

对于有符号且非负的 a ,若 a * 2 b
在返回类型的无符号版本中可表示,则该值经 转换 为有符号后即为 a << b 的值(这使得将 INT_MIN 创建为 1 << 31 合法);否则行为未定义。

对于负值 a a << b 的行为未定义。

对于无符号类型 a 及有符号且非负的 a a >> b 的值为 a/2 b
的整数部分。

对于负值 a a >> b 的值由实现定义(在大多数实现中执行算术右移,因此结果保持为负)。

(until C++20)

a << b 的值为与 a * 2 b
2 N
取模同余的唯一值,其中 N 是返回类型的位数(即执行按位左移,且移出目标类型的位被丢弃)。

a >> b 的值为 a/2 b
向负无穷取整的结果(换言之,对有符号 a 的右移是算术右移)。

(since C++20)

结果的类型与 lhs 的类型相同。

重载

针对用户定义运算符的重载决议 中,对于每对提升后的整型类型 L R ,以下函数签名会参与重载决议:

L operator << ( L, R )
L operator >> ( L, R )
(注:根据要求,HTML标签、属性及 标签内的C++代码均未翻译,仅对页面结构进行了中文说明。实际内容中无需要翻译的自然语言文本)
#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> 的公开成员函数)

加法运算符

对时间点执行加减运算
(函数模板)
实现以时长为参数的算术运算
(函数模板)
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> 的公开成员函数)

流插入/提取运算符

在整个标准库中,按位移位运算符通常被重载为以I/O流( std:: ios_base & 或其派生类之一)作为左操作数和返回类型。这类运算符被称为 流插入 流提取 运算符:

提取格式化数据
( std::basic_istream<CharT,Traits> 的公开成员函数)
提取字符和字符数组
(函数模板)
插入格式化数据
( std::basic_ostream<CharT,Traits> 的公开成员函数)
插入字符数据或插入到右值流
(函数模板)
序列化和反序列化复数
(函数模板)
执行位集的流输入和输出
(函数模板)
对字符串执行流输入和输出
(函数模板)
对伪随机数引擎执行流输入和输出
(函数模板)
对伪随机数分布执行流输入和输出
(函数模板)

缺陷报告

以下行为变更缺陷报告被追溯应用于先前发布的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 的无符号整数
应遵守模 2 n 算术规则
适用于所有无符号整数
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 + = b
a - = b
a * = b
a / = b
a % = b
a & = b
a | = b
a ^ = b
a <<= b
a >>= b

++ a
-- a
a ++
a --

+ a
- a
a + b
a - b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b

! a
a && b
a || b

a == b
a ! = b
a < b
a > b
a <= b
a >= b
a <=> b

a [ ... ]
* a
& a
a - > b
a. b
a - > * b
a. * b

函数调用

a ( ... )
逗号

a, b
条件

a ? b : c
特殊运算符

static_cast 将一种类型转换为另一种相关类型
dynamic_cast 在继承层次结构内进行转换
const_cast 添加或移除 cv 限定符
reinterpret_cast 将类型转换为不相关类型
C风格转换 通过混合使用 static_cast const_cast reinterpret_cast 将一种类型转换为另一种类型
new 创建具有动态存储期的对象
delete 销毁先前由 new 表达式创建的对象并释放获取的内存区域
sizeof 查询类型的大小
sizeof... 查询 参数包 的大小 (C++11 起)
typeid 查询类型的类型信息
noexcept 检查表达式是否能抛出异常 (C++11 起)
alignof 查询类型的对齐要求 (C++11 起)

C 文档 关于 算术运算符