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

Devuelve el resultado de una operación aritmética específica.

Nombre del operador Sintaxis Ejemplos de prototipo (para class T )
Dentro de la definición de clase Fuera de la definición de clase
Más unario + a T T :: operator + ( ) const ; T operator + ( const T & a ) ;
Menos unario - a T T :: operator - ( ) const ; T operator - ( const T & a ) ;
Adición a + b T T :: operator + ( const T2 & b ) const ; T operator + ( const T & a, const T2 & b ) ;
Resta a - b T T :: operator - ( const T2 & b ) const ; T operator - ( const T & a, const T2 & b ) ;
Multiplicación a * b T T :: operator * ( const T2 & b ) const ; T operator * ( const T & a, const T2 & b ) ;
División a / b T T :: operator / ( const T2 & b ) const ; T operator / ( const T & a, const T2 & b ) ;
Resto a % b T T :: operator % ( const T2 & b ) const ; T operator % ( const T & a, const T2 & b ) ;
NOT a nivel de bits ~a T T :: operator ~ ( ) const ; T operator~ ( const T & a ) ;
AND bit a bit a & b T T :: operator & ( const T2 & b ) const ; T operator & ( const T & a, const T2 & b ) ;
OR bit a bit a | b T T :: operator | ( const T2 & b ) const ; T operator | ( const T & a, const T2 & b ) ;
XOR bit a bit a ^ b T T :: operator ^ ( const T2 & b ) const ; T operator ^ ( const T & a, const T2 & b ) ;
Desplazamiento a la izquierda bit a bit a << b T T :: operator << ( const T2 & b ) const ; T operator << ( const T & a, const T2 & b ) ;
Desplazamiento a la derecha bit a bit a >> b T T :: operator >> ( const T2 & b ) const ; T operator >> ( const T & a, const T2 & b ) ;
Notas
  • Todos los operadores en esta tabla son sobrecargables .
  • Todos los operadores incorporados devuelven valores, y la mayoría de las sobrecargas definidas por el usuario también devuelven valores para que los operadores definidos por el usuario puedan usarse de la misma manera que los incorporados. Sin embargo, en una sobrecarga de operador definida por el usuario, se puede utilizar cualquier tipo como tipo de retorno (incluyendo void ). En particular, las sobrecargas de inserción de flujo y extracción de flujo de operator << y operator >> devuelven T& .
  • T2 puede ser cualquier tipo incluyendo T .

Contenidos

Explicación general

Todos los operadores aritméticos incorporados calculan el resultado de una operación aritmética específica y devuelven su resultado. Los argumentos no se modifican.

Conversiones

Si el operando pasado a un operador aritmético incorporado es de tipo entero o de enumeración no acotada, entonces antes de cualquier otra acción (pero después de la conversión de lvalue a rvalue, si es aplicable), el operando sufre promoción integral . Si un operando tiene tipo array o función, se aplican las conversiones array-a-puntero y función-a-puntero .

Para los operadores binarios (excepto desplazamientos), si los operandos promocionados tienen tipos diferentes, usual arithmetic conversions son aplicadas.

Desbordamientos

La aritmética de enteros sin signo siempre se realiza módulo 2 n
donde n es el número de bits en ese entero particular. Por ejemplo, para unsigned int , sumar uno a UINT_MAX da como resultado 0 , y restar uno de 0 da como resultado UINT_MAX .

Cuando una operación aritmética con enteros con signo desborda (el resultado no cabe en el tipo de resultado), el comportamiento es indefinido — las posibles manifestaciones de dicha operación incluyen:

  • se ajusta según las reglas de la representación (normalmente complemento a dos ),
  • genera una trampa — en algunas plataformas o debido a opciones del compilador (por ejemplo -ftrapv en GCC y Clang),
  • satura al valor mínimo o máximo (en muchos DSPs),
  • es completamente optimizado por el compilador .

Entorno de punto flotante

Si #pragma STDC FENV_ACCESS es compatible y está establecido en ON , todos los operadores aritméticos de punto flotante obedecen la dirección de redondeo actual de punto flotante y reportan errores aritméticos de punto flotante según lo especificado en math_errhandling a menos que formen parte de un inicializador estático (en cuyo caso no se generan excepciones de punto flotante y el modo de redondeo es al más cercano).

Contracción de punto flotante

A menos que #pragma STDC FP_CONTRACT sea compatible y esté establecido en OFF , toda aritmética de punto flotante puede realizarse como si los resultados intermedios tuvieran rango y precisión infinitos, es decir, se permiten optimizaciones que omiten errores de redondeo y excepciones de punto flotante. Por ejemplo, C++ permite la implementación de ( x * y ) + z con una única instrucción de CPU de multiplicación-fusión-suma o la optimización de a = x * x * x * x ; como tmp = x * x ; a = tmp * tmp .

Sin relación con la contratación, los resultados intermedios de la aritmética de punto flotante pueden tener un rango y precisión diferentes a los indicados por su tipo, consulte FLT_EVAL_METHOD .

Formalmente, el estándar de C++ no ofrece ninguna garantía sobre la precisión de las operaciones de punto flotante.

Operadores aritméticos unarios

Las expresiones de operadores aritméticos unarios tienen la forma

+ expresión (1)
- expresión (2)
1) Operador unario más (promoción).
2) Menos unario (negación).

Los operadores unarios + y - tienen mayor precedencia que todos los operadores aritméticos binarios, por lo que la expresión no puede contener operadores aritméticos binarios de nivel superior. Estos operadores se asocian de derecha a izquierda:

+a - b; // equivalente a (+a) - b, NO a +(a - b)
-c + d; // equivalente a (-c) + d, NO a -(c + d)
+-e; // equivalente a +(-e), el operador unario + no tiene efecto si "e" es un tipo básico
     // porque cualquier promoción posible se realiza durante la negación

Operadores aritméticos unarios incorporados

1) Para el operador unario de suma incorporado, expression debe ser un prvalue de tipo aritmético, enumeración sin ámbito o puntero. Se realiza promoción integral en expression si tiene tipo integral o de enumeración sin ámbito. El tipo del resultado es el tipo (posiblemente promocionado) de expression .
El resultado de la promoción incorporada es el valor de expresión . La operación unaria incorporada es no-op si el operando es un prvalue de un tipo integral promocionado o un tipo puntero. De lo contrario, el tipo o categoría de valor del operando es cambiado por promoción integral o conversión lvalue-a-rvalue, array-a-puntero, función-a-puntero, o conversión definida por el usuario. Por ejemplo, char es convertido a int , y la expresión lambda no genérica sin captura lambda expression es convertida a puntero a función (since C++11) en expresiones de suma unaria.
2) Para el operador unario menos incorporado, expression debe ser un prvalue de tipo aritmético o enumeración sin ámbito. Se realiza promoción integral en expression . El tipo del resultado es el tipo promocionado de expression .
El resultado de la negación incorporada es el negativo de la expresión promocionada. Para un valor sin signo a , el valor de - a es 2 N
-a
, donde N es el número de bits después de la promoción.
  • En otras palabras, el resultado es el complemento a dos del operando (donde el operando y el resultado se consideran como sin signo).

Sobrecargas

En la resolución de sobrecarga contra operadores definidos por el usuario , para cada tipo aritmético promovido sin calificación cv A y para cada tipo T , las siguientes firmas de función participan en la resolución de sobrecarga:

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, 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';
}

Salida posible:

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

Operadores aditivos

Las expresiones con operadores aditivos tienen la forma

lhs + rhs (1)
lhs - rhs (2)
1) Binario más (suma).
2) Menos binario (resta).

Los operadores binarios + y - tienen mayor precedencia que todos los demás operadores aritméticos binarios excepto * , / y % . Estos operadores se asocian de izquierda a derecha:

a + b * c;  // equivalente a a + (b * c),  NO (a + b) * c
d / e - f;  // equivalente a (d / e) - f,  NO d / (e - f)
g + h >> i; // equivalente a (g + h) >> i, NO g + (h >> i)
j - k + l - m; // equivalente a ((j - k) + l) - m

Operadores aditivos incorporados

Para los operadores binarios incorporados de suma y resta, tanto lhs como rhs deben ser prvalues, y debe cumplirse una de las siguientes condiciones:

  • Ambos operandos tienen tipo aritmético o de enumeración no acotada. En este caso, usual arithmetic conversions se realizan en ambos operandos.
  • Exactamente un operando tiene tipo integral o de enumeración no acotada. En este caso, integral promotion se aplica a ese operando.

En la descripción restante de esta sección, "operando(s)", lhs y rhs se refieren a los operandos convertidos o promovidos.

1) Para la suma incorporada, debe satisfacerse una de las siguientes condiciones:
  • Ambos operandos tienen tipo aritmético. En este caso, el resultado es la suma de los operandos.
  • Un operando es un puntero a un tipo de objeto completamente definido, y el otro operando tiene tipo integral. En este caso, el valor integral se suma al puntero (ver pointer arithmetic ).
2) Para la resta incorporada, debe cumplirse una de las siguientes condiciones:
  • Ambos operandos tienen tipo aritmético. En este caso, el resultado es la diferencia resultante de la resta de rhs de lhs .
  • lhs es un puntero a un tipo de objeto completamente definido, y rhs tiene tipo integral. En este caso, el valor integral se resta del puntero (ver aritmética de punteros ).
  • Ambos operandos son punteros a versiones calificadas o no calificadas con cv del mismo tipo de objeto completamente definido. En este caso rhs se resta de lhs (ver aritmética de punteros ).

Si ambos operandos tienen un tipo de punto flotante, y el tipo admite aritmética de punto flotante IEEE (ver std::numeric_limits::is_iec559 ):

  • Si un operando es NaN, el resultado es NaN.
  • Infinito menos infinito es NaN, y FE_INVALID se activa.
  • Infinito más infinito negativo es NaN, y FE_INVALID se activa.

Aritmética de punteros

Cuando una expresión J que tiene tipo integral se suma o resta de una expresión P de tipo puntero, el resultado tiene el tipo de P .

  • Si P se evalúa como un valor de puntero nulo y J se evalúa como 0 , el resultado es un valor de puntero nulo.
  • De lo contrario, si P apunta al elemento i -ésimo de un objeto array x con n elementos, dado el valor de J como j , P se suma o resta de la siguiente manera:
  • Las expresiones P + J y J + P
  • apuntan al elemento i+j de x si i + j está en [ 0 , n ) , y
  • son punteros más allá del último elemento de x si i + j es n .
  • La expresión P - J
  • apunta al elemento i-j de x si i - j está en [ 0 , n ) , y
  • es un puntero más allá del último elemento de x si i - j es n .
  • Otros valores de j resultan en comportamiento indefinido.
  • De lo contrario, si P apunta a un objeto completo, un subobjeto de clase base o un subobjeto de miembro y , dado el valor de J como j , P se suma o resta de la siguiente manera:
  • Las expresiones P + J y J + P
  • apuntan a y si j es 0 , y
  • son punteros más allá del final de y si j es 1 .
  • La expresión P - J
  • apunta a y si j es 0 , y
  • es un puntero más allá del final de y si j es - 1 .
  • Otros valores de j resultan en comportamiento indefinido.
  • De lo contrario, si P es un puntero más allá del final de un objeto z , dado el valor de J como j :
  • Si z es un objeto de array con n elementos, P se suma o resta de la siguiente manera:
  • Las expresiones P + J y J + P
  • apuntan al elemento n+j de z si n + j está en [ 0 , n ) , y
  • son punteros más allá del último elemento de z si j es 0 .
  • La expresión P - J
  • apunta al elemento n-j de z si n - j está en [ 0 , n ) , y
  • es un puntero más allá del último elemento de z si j es 0 .
  • Otros valores de j resultan en comportamiento indefinido.
  • En caso contrario, P se suma o resta de la siguiente manera:
  • Las expresiones P + J y J + P
  • apuntan a z si j es - 1 , y
  • son punteros más allá del final de z si j es 0 .
  • La expresión P - J
  • apunta a z si j es 1 , y
  • es un puntero más allá del final de z si j es 0 .
  • Otros valores de j resultan en comportamiento indefinido.
  • De lo contrario, el comportamiento es indefinido.

Cuando dos expresiones de puntero P y Q se restan, el tipo del resultado es std::ptrdiff_t .

  • Si P y Q ambos evalúan a valores de puntero nulo , el resultado es 0 .
  • De lo contrario, si P y Q apuntan, respectivamente, al i -ésimo y j -ésimo elemento del array del mismo objeto array x , la expresión P - Q tiene el valor i − j .
  • Si i − j no es representable mediante std::ptrdiff_t , el comportamiento es indefinido.
  • De lo contrario, si P y Q apuntan al mismo objeto completo, subobjeto de clase base o subobjeto de miembro, el resultado es 0 .
  • De lo contrario, el comportamiento es indefinido.

Estos operadores de aritmética de punteros permiten que los punteros satisfagan los LegacyRandomAccessIterator requisitos.

Para la suma y la resta, si P o Q tienen tipo "puntero a (posiblemente calificado con cv) T ", donde T y el tipo del elemento del array no son similares , el comportamiento es indefinido:

int arr[5] = {1, 2, 3, 4, 5};
unsigned int *p = reinterpret_cast<unsigned int*>(arr + 1);
unsigned int k = *p; // CORRECTO, el valor de "k" es 2
unsigned int *q = p + 1; // comportamiento indefinido: "p" apunta a int, no a unsigned int

Sobrecargas

En la resolución de sobrecarga frente a operadores definidos por el usuario , para cada par de tipos aritméticos promocionados L y R y para cada tipo de objeto T , las siguientes firmas de función participan en la resolución de sobrecarga:

LR operador + ( L, R )
LR operador - ( L, R )
T * operador + ( T * , std:: ptrdiff_t )
T * operador + ( std:: ptrdiff_t , T * )
T * operador - ( T * , std:: ptrdiff_t )
std:: ptrdiff_t operador - ( T * , T * )

donde LR es el resultado de las conversiones aritméticas usuales aplicadas a L y 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';
}

Salida:

 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

Operadores multiplicativos

Las expresiones con operador multiplicativo tienen la forma

lhs * rhs (1)
lhs / rhs (2)
lhs % rhs (3)
1) Multiplicación.
2) División.
3) Resto.

Los operadores multiplicativos tienen mayor precedencia que todos los demás operadores aritméticos binarios. Estos operadores se asocian de izquierda a derecha:

a + b * c;  // equivalente a a + (b * c), NO (a + b) * c
d / e - f;  // equivalente a (d / e) - f, NO d / (e - f)
g % h >> i; // equivalente a (g % h) >> i, NO g % (h >> i)
j * k / l % m; // equivalente a ((j * k) / l) % m

Operadores multiplicativos incorporados

Para los operadores de multiplicación y división incorporados, ambos operandos deben tener tipo aritmético o de enumeración no delimitada. Para el operador de resto incorporado, ambos operandos deben tener tipo integral o de enumeración no delimitada. Conversiones aritméticas usuales se realizan en ambos operandos.

En la descripción restante de esta sección, "operando(s)", lhs y rhs se refieren a los operandos convertidos.

1) El resultado de la multiplicación incorporada es el producto de los operandos.
Si ambos operandos tienen un tipo de punto flotante, y el tipo soporta aritmética de punto flotante IEEE (ver std::numeric_limits::is_iec559 ):
  • La multiplicación de un NaN por cualquier número da como resultado NaN.
  • La multiplicación de infinito por cero da como resultado NaN y se genera FE_INVALID .
2) El resultado de la división incorporada es lhs dividido por rhs . Si rhs es cero, el comportamiento es indefinido.
Si ambos operandos tienen un tipo integral, el resultado es el cociente algebraico (realiza división entera): el cociente se trunca hacia cero (la parte fraccionaria se descarta).
Si ambos operandos tienen un tipo de punto flotante, y el tipo soporta aritmética de punto flotante IEEE (ver std::numeric_limits::is_iec559 ):
  • Si un operando es NaN, el resultado es NaN.
  • Dividir un número no-cero por ±0.0 da el infinito con signo correcto y FE_DIVBYZERO se activa.
  • Dividir 0.0 por 0.0 da NaN y FE_INVALID se activa.
3) El resultado del resto incorporado es el resto de la división entera de lhs entre rhs . Si rhs es cero, el comportamiento es indefinido.
Si a / b es representable en el tipo de resultado, ( a / b ) * b + a % b == a .
Si a / b no es representable en el tipo de resultado, el comportamiento tanto de a / b como de a % b es indefinido (esto significa que INT_MIN % - 1 es indefinido en sistemas de complemento a dos).

Nota: Hasta que CWG issue 614 fue resuelto ( N2757 ), si uno o ambos operandos del operador binario % eran negativos, el signo del resto estaba definido por la implementación, ya que depende de la dirección de redondeo de la división entera. La función std::div proporcionaba un comportamiento bien definido en ese caso.

Nota: para el resto de punto flotante, consulta std::remainder y std::fmod .

Sobrecargas

En la resolución de sobrecarga contra operadores definidos por el usuario , para cada par de tipos aritméticos promocionados LA y RA y para cada par de tipos integrales promocionados LI y RI las siguientes firmas de función participan en la resolución de sobrecarga:

LRA operator * ( LA, RA )
LRA operator / ( LA, RA )
LRI operator % ( LI, RI )

donde LRx es el resultado de las conversiones aritméticas usuales aplicadas a Lx y 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';
}

Salida:

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

Operadores lógicos bit a bit

Las expresiones de operadores lógicos bit a bit tienen la forma

~ rhs (1)
lhs & rhs (2)
lhs | rhs (3)
lhs ^ rhs (4)
1) NOT a nivel de bits.
2) AND bit a bit.
3) OR bit a bit.
4) XOR bit a bit.

El operador NOT a nivel de bits tiene mayor precedencia que todos los operadores aritméticos binarios. Se asocia de derecha a izquierda:

~a - b; // equivalente a (~a) - b, NO ~(a - b)
~c * d; // equivalente a (~c) * d, NO ~(c * d)
~-e; // equivalente a ~(-e)

Existe una ambigüedad en la gramática cuando ~ es seguido por un nombre de tipo o un especificador decltype (desde C++11) : puede ser el operador~ o iniciar un identificador de destructor ). La ambigüedad se resuelve tratando ~ como operador~. ~ puede iniciar un identificador de destructor solo en lugares donde formar un operador~ es sintácticamente inválido.

Todos los demás operadores lógicos bit a bit tienen menor precedencia que todos los demás operadores aritméticos binarios. El AND bit a bit tiene mayor precedencia que el XOR bit a bit, que tiene mayor precedencia que el OR bit a bit. Asocian de izquierda a derecha:

a & b * c;  // equivalente a a & (b * c),  NO (a & b) * c
d / e ^ f;  // equivalente a (d / e) ^ f,  NO d / (e ^ f)
g << h | i; // equivalente a (g << h) | i, NO g << (h | i)
j & k & l; // equivalente a (j & k) & l
m | n ^ o  // equivalente a m | (n ^ o)

Operadores lógicos bit a bit incorporados

Para el operador NOT bit a bit incorporado, rhs debe ser un prvalue de tipo entero o enumeración sin ámbito, y se realiza promoción entera en rhs . Para otros operadores lógicos bit a bit incorporados, ambos operandos deben tener tipo entero o enumeración sin ámbito, y conversiones aritméticas usuales se realizan en ambos operandos.

En la descripción restante de esta sección, "operando(s)", lhs y rhs se refieren a los operandos convertidos o promovidos.

1) Dado el operando como x y el resultado de la operación NOT bit a bit incorporada como r . Para cada coeficiente x_i de la representación en base-2 de x , el coeficiente correspondiente r_i de la representación en base-2 de r es 1 si x_i es 0 , y 0 en caso contrario.
  • En otras palabras, el resultado es el complemento a uno del operando (donde el operando y el resultado se consideran como sin signo).
El tipo del resultado r es el tipo del operando x .
2-4) Dados los operandos como x y y respectivamente y el resultado de las operaciones lógicas binarias bit a bit integradas como r . Para cada par de coeficientes x_i y y_i de las representaciones en base-2 de x y y respectivamente, el coeficiente correspondiente r_i de la representación en base-2 de r es
2) 1 si ambos x_i y y_i son 1 , y 0 en caso contrario.
3) 1 si al menos uno de x_i y y_i es 1 , y 0 en caso contrario.
4) 1 si uno (pero no ambos) de x_i y y_i es 1 , y 0 en caso contrario.
El tipo del resultado r es el tipo de los operandos x y y .

Sobrecargas

En la resolución de sobrecarga frente a operadores definidos por el usuario , para cada par de tipos integrales promocionados L y R las siguientes firmas de función participan en la resolución de sobrecarga:

R operador~ ( R )
LR operador & ( L, R )
LR operador ^ ( L, R )
LR operador | ( L, R )

donde LR es el resultado de las conversiones aritméticas usuales aplicadas a L y 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
              << "Máscara: " << mask << std::setw(49) << bin16(mask) << "\n"
                 "Valor: " << x0 << std::setw(42) << bin32(x0) << "\n"
                 "Estableciendo bits: " << x1 << std::setw(35) << bin32(x1) << "\n"
                 "Limpiando bits: " << x2 << std::setw(34) << bin32(x2) << "\n"
                 "Seleccionando bits: " << x3 << std::setw(39) << bin32(x3) << "\n"
                 "Operación XOR en bits: " << x4 << std::setw(35) << bin32(x4) << "\n"
                 "Invirtiendo bits: " << x5 << std::setw(33) << bin32(x5) << '\n';
}

Salida:

Máscara: 0xf0                                 0000000011110000
Valor: 0x12345678          00010010001101000101011001111000
Estableciendo bits: 0x123456f8   00010010001101000101011011111000
Limpiando bits: 0x12345608  00010010001101000101011000001000
Seleccionando bits: 0x70       00000000000000000000000001110000
Operación XOR en bits: 0x12345688   00010010001101000101011010001000
Invirtiendo bits: 0xedcba987 11101101110010111010100110000111

Operadores de desplazamiento bit a bit

Las expresiones del operador de desplazamiento bit a bit tienen la forma

lhs << rhs (1)
lhs >> rhs (2)
1) Desplazamiento a la izquierda bit a bit.
2) Desplazamiento a la derecha bit a bit.

Los operadores de desplazamiento bit a bit tienen mayor precedencia que los operadores lógicos bit a bit, pero menor precedencia que los operadores aditivos y multiplicativos. Estos operadores se asocian de izquierda a derecha:

a >> b * c;  // equivalente a a >> (b * c),  NO (a >> b) * c
d << e & f;  // equivalente a (d << e) & f,  NO d << (e & f)
g << h >> i; // equivalente a (g << h) >> i, NO g << (h >> i)

Operadores de desplazamiento bit a bit incorporados

Para los operadores de desplazamiento bit a bit incorporados, ambos operandos deben ser prvalues de tipo entero o enumeración sin ámbito. Se realizan promociones enteras en ambos operandos.

En la descripción restante de esta sección, "operando(s)", a , b , lhs y rhs se refieren a los operandos convertidos o promovidos.

Si el valor de rhs es negativo o no es menor que el número de bits en lhs , el comportamiento es indefinido.

Para a sin signo, el valor de a << b es el valor de a * 2 b
, reducido módulo 2 N
donde N es el número de bits en el tipo de retorno (es decir, se realiza un desplazamiento a la izquierda bit a bit y los bits que se desplazan fuera del tipo de destino se descartan).

Para a con signo y no negativo, si a * 2 b
es representable en la versión sin signo del tipo de retorno, entonces ese valor, convertido a con signo, es el valor de a << b (esto hace que sea legal crear INT_MIN como 1 << 31 ); de lo contrario, el comportamiento es indefinido.

Para a negativo, el comportamiento de a << b es indefinido.

Para a sin signo y para a con signo y no negativo, el valor de a >> b es la parte entera de a/2 b
.

Para a negativo, el valor de a >> b está definido por la implementación (en la mayoría de las implementaciones, esto realiza un desplazamiento aritmético a la derecha, de modo que el resultado permanece negativo).

(hasta C++20)

El valor de a << b es el valor único congruente con a * 2 b
módulo 2 N
donde N es el número de bits en el tipo de retorno (es decir, se realiza un desplazamiento a la izquierda bit a bit y los bits que se desplazan fuera del tipo de destino se descartan).

El valor de a >> b es a/2 b
, redondeado hacia menos infinito (en otras palabras, el desplazamiento a la derecha en a con signo es un desplazamiento aritmético a la derecha).

(desde C++20)

El tipo del resultado es el de lhs .

Sobrecargas

En la resolución de sobrecarga frente a operadores definidos por el usuario , para cada par de tipos integrales promocionados L y R , las siguientes firmas de función participan en la resolución de sobrecarga:

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" // desbordamiento en unsigned
                 "0x10 << 10 = " << (c << 10) << '\n';   // char se promueve a int
    long long ll = -1000;
    std::cout << std::dec << "-1000 >> 1 = " << (ll >> ONE) << '\n';
}

Salida:

0x123 << 1 = 0x246
0x123 << 63 = 0x8000000000000000
0x10 << 10 = 0x4000
-1000 >> 1 = -500

Biblioteca estándar

Los operadores aritméticos están sobrecargados para muchos tipos de la biblioteca estándar.

Operadores aritméticos unarios

implementa + unario y - unario
(función miembro pública de std::chrono::duration<Rep,Period> )
aplica operadores unarios a números complejos
(plantilla de función)
aplica un operador aritmético unario a cada elemento del valarray
(función miembro pública de std::valarray<T> )

Operadores aditivos

realiza operaciones de suma y resta que involucran un punto temporal
(plantilla de función)
implementa operaciones aritméticas con duraciones como argumentos
(plantilla de función)
suma o resta un year_month_day y cierto número de años o meses
(función)
concatena dos cadenas, una cadena y un char , o una cadena y string_view
(plantilla de función)
avanza o decrementa el iterador
(función miembro pública de std::reverse_iterator<Iter> )
avanza o decrementa el iterador
(función miembro pública de std::move_iterator<Iter> )
realiza operaciones aritméticas con números complejos sobre dos valores complejos o un complejo y un escalar
(plantilla de función)
aplica operadores binarios a cada elemento de dos valarrays, o un valarray y un valor
(plantilla de función)

Operadores multiplicativos

implementa operaciones aritméticas con duraciones como argumentos
(plantilla de función)
realiza operaciones aritméticas con números complejos sobre dos valores complejos o un complejo y un escalar
(plantilla de función)
aplica operadores binarios a cada elemento de dos valarrays, o un valarray y un valor
(plantilla de función)

Operadores lógicos bit a bit

realiza operaciones binarias AND, OR, XOR y NOT
(función miembro pública de std::bitset<N> )
realiza operaciones lógicas binarias en bitsets
(plantilla de función)
aplica un operador aritmético unario a cada elemento del valarray
(función miembro pública de std::valarray<T> )
aplica operadores binarios a cada elemento de dos valarrays, o un valarray y un valor
(plantilla de función)

Operadores de desplazamiento bit a bit

aplica operadores binarios a cada elemento de dos valarrays, o un valarray y un valor
(plantilla de función)
realiza desplazamiento binario a la izquierda y desplazamiento a la derecha
(función miembro pública de std::bitset<N> )

Operadores de inserción/extracción de flujo

A lo largo de la biblioteca estándar, los operadores de desplazamiento bit a bit comúnmente se sobrecargan con flujos de E/S ( std:: ios_base & o una de las clases derivadas de él) como tanto el operando izquierdo como el tipo de retorno. Dichos operadores se conocen como operadores de inserción de flujo y operadores de extracción de flujo :

extrae datos formateados
(función miembro pública de std::basic_istream<CharT,Traits> )
extrae caracteres y arreglos de caracteres
(plantilla de función)
inserta datos formateados
(función miembro pública de std::basic_ostream<CharT,Traits> )
inserta datos de caracteres o inserta en flujo de valor R
(plantilla de función)
serializa y deserializa un número complejo
(plantilla de función)
realiza entrada y salida de flujo de conjuntos de bits
(plantilla de función)
realiza entrada y salida de flujo en cadenas
(plantilla de función)
realiza entrada y salida de flujo en motor de números pseudoaleatorios
(plantilla de función)
realiza entrada y salida de flujo en distribución de números pseudoaleatorios
(plantilla de función)

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares publicados anteriormente de C++.

DR Aplicado a Comportamiento publicado Comportamiento correcto
CWG 614 C++98 el cociente algebraico de la división entera se
redondeaba en dirección definida por la implementación
el cociente algebraico de la división
entera se trunca hacia cero
(la parte fraccionaria se descarta)
CWG 1450 C++98 el resultado de a / b no estaba especificado si
no es representable en el tipo de resultado
el comportamiento tanto de a / b como de
a % b es indefinido en este caso
CWG 1457 C++98 el comportamiento de desplazar el bit 1 más a la
izquierda de un valor con signo positivo al bit de signo era indefinido
se define correctamente
CWG 1504 C++98 un puntero a un subobjeto de clase base de un elemento
de array podía usarse en aritmética de punteros
el comportamiento es
indefinido en este caso
CWG 1515 C++98 solo los enteros sin signo declarados unsigned
deberían obedecer las leyes de aritmética módulo 2 n
aplica a todos los enteros sin signo
CWG 1642 C++98 los operadores aritméticos permiten que sus operandos sean lvalues algunos operandos deben ser rvalues
CWG 1865 C++98 la resolución de CWG issue 1504 hizo que los comportamientos
de aritmética de punteros que involucran punteros a elementos de array
fueran indefinidos si el tipo apuntado y el tipo del elemento de array
tienen diferentes calificaciones cv en niveles no superiores
se define correctamente
CWG 1971 C++98 no estaba claro si la regla que resuelve la
ambigüedad de ~ aplica a casos como ~X ( 0 )
la regla aplica a tales casos
CWG 2419 C++98 un puntero a objeto no-array solo se trataba como un
puntero al primer elemento de un array con tamaño 1
en aritmética de punteros si el puntero se obtiene mediante &
aplica a todos los punteros
a objetos no-array
CWG 2626 C++98 el resultado del operator~ incorporado era simplemente
'complemento a uno' sin una definición adecuada
el resultado se expresa en términos
de la representación en base 2
CWG 2724 C++20 la dirección de redondeo del desplazamiento aritmético a la derecha no estaba clara se aclara
CWG 2853 C++98 un puntero más allá del final de un objeto no podía
sumarse o restarse con un entero
sí puede

Véase también

Precedencia de operadores

Sobrecarga de operadores

Operadores comunes
asignación incremento
decremento
aritméticos lógicos comparación acceso a
miembros
otros

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

llamada a función

a ( ... )
coma

a, b
condicional

a ? b : c
Operadores especiales

static_cast convierte un tipo a otro tipo relacionado
dynamic_cast convierte dentro de jerarquías de herencia
const_cast añade o elimina cv -calificadores
reinterpret_cast convierte un tipo a un tipo no relacionado
Conversión estilo C convierte un tipo a otro mediante una mezcla de static_cast , const_cast , y reinterpret_cast
new crea objetos con duración de almacenamiento dinámico
delete destruye objetos previamente creados por la expresión new y libera el área de memoria obtenida
sizeof consulta el tamaño de un tipo
sizeof... consulta el tamaño de un pack (desde C++11)
typeid consulta la información de tipo de un tipo
noexcept comprueba si una expresión puede lanzar una excepción (desde C++11)
alignof consulta los requisitos de alineación de un tipo (desde C++11)

Documentación de C para Operadores aritméticos