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 ) ;
비트 NOT ~a T T :: operator ~ ( ) const ; T operator~ ( const T & a ) ;
비트 AND a & b T T :: operator & ( const T2 & b ) const ; T operator & ( const T & a, const T2 & b ) ;
비트 OR a | b T T :: operator | ( const T2 & b ) const ; T operator | ( const T & a, const T2 & b ) ;
비트별 XOR 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 를 포함한 모든 타입이 될 수 있습니다.

목차

일반적인 설명

모든 내장 산술 연산자는 특정 산술 연산의 결과를 계산하고 그 결과를 반환합니다. 인수는 수정되지 않습니다.

변환

내장 산술 연산자에 전달된 피연산자가 정수형 또는 비범위 열거형인 경우, 다른 모든 동작 전에(그러나 적용 가능한 경우 lvalue-to-rvalue 변환 이후) 피연산자는 integral promotion 을 거칩니다. 피연산자가 배열 또는 함수 타입을 가지는 경우, array-to-pointer function-to-pointer 변환이 적용됩니다.

이항 연산자(시프트 연산 제외)의 경우, 승격된 피연산자들의 타입이 서로 다르면 일반 산술 변환 이 적용됩니다.

오버플로우

부호 없는 정수 연산은 항상 modulo 2 n
으로 수행되며, 여기서 n은 해당 정수의 비트 수입니다. 예를 들어 unsigned int 의 경우, UINT_MAX 에 1을 더하면 0 이 되고, 0 에서 1을 빼면 UINT_MAX 가 됩니다.

부호 있는 정수 산술 연산이 오버플로될 때(결과가 결과 타입에 맞지 않음), 그 동작은 정의되지 않습니다 — 이러한 연산의 가능한 현상으로는 다음이 포함됩니다:

  • 이는 표현 방식의 규칙에 따라 감싸기(wrap around)됩니다 (일반적으로 two's complement ).
  • 트랩(trap)됩니다 — 일부 플랫폼이나 컴파일러 옵션에 의해 (예: GCC와 Clang의 -ftrapv ).
  • 최소값 또는 최대값으로 포화(saturate)됩니다 (많은 DSP에서).
  • 컴파일러에 의해 완전히 optimized out by the compiler 됩니다.

부동소수점 환경

만약 #pragma STDC FENV_ACCESS 가 지원되고 ON 으로 설정된 경우, 모든 부동 소수점 연산자는 현재 부동 소수점 반올림 방향 을 따르며, math_errhandling 에 지정된 대로 부동 소수점 산술 오류를 보고합니다. 단, 정적 초기화 의 일부인 경우는 예외입니다(이 경우 부동 소수점 예외가 발생하지 않으며 반올림 모드는 가장 가까운 값으로 설정됩니다).

부동 소수점 축약

#pragma STDC FP_CONTRACT 가 지원되고 OFF 로 설정되지 않는 한, 모든 부동 소수점 연산은 중간 결과가 무한한 범위와 정밀도를 가진 것처럼 수행될 수 있습니다. 즉, 반올림 오류와 부동 소수점 예외를 생략하는 최적화가 허용됩니다. 예를 들어, C++은 ( x * y ) + z 를 단일 FMA(Fused Multiply-Add) CPU 명령어로 구현하거나 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"가 built-in type인 경우 단항 +는 no-op임
     // 부정 연산 수행 중에 가능한 모든 promotion이 이미 이루어지기 때문

내장 단항 산술 연산자

1) 내장 단항 플러스 연산자의 경우, expression 은 산술 타입, 범위 없는 열거형 또는 포인터 타입의 prvalue여야 합니다. expression 이 정수형 또는 범위 없는 열거형 타입을 가질 경우 정수 승격이 수행됩니다. 결과의 타입은 expression 의 (승격될 수 있는) 타입입니다.
내장 승격의 결과는 expression 의 값입니다. 피연산자가 승격된 정수 계열 타입이나 포인터 타입의 prvalue인 경우 내장 단항 연산은 no-op입니다. 그렇지 않으면 피연산자의 타입이나 값 범주는 정수 승격, lvalue-to-rvalue, array-to-pointer, function-to-pointer 또는 사용자 정의 변환에 의해 변경됩니다. 예를 들어, char int 로 변환되고, 비제네릭 캡처 없는 lambda expression 는 함수 포인터로 변환됩니다 (C++11부터) 단항 플러스 표현식에서.
2) 내장 단항 마이너스 연산자의 경우, expression 은 산술 타입이나 범위 없는 열거형 타입의 prvalue여야 합니다. expression 에는 정수 승격이 수행됩니다. 결과의 타입은 expression 의 승격된 타입과 동일합니다.
내장 부정 연산의 결과는 승격된 expression 의 음수 값입니다. 부호 없는 a 에 대해, - a 의 값은 2 N
-a
입니다. 여기서 N 은 승격 후의 비트 수입니다.
  • 다른 말로, 결과는 피연산자의 2의 보수입니다(피연산자와 결과는 부호 없는 것으로 간주).

오버로드

사용자 정의 연산자에 대한 오버로드 해결 에서, 모든 cv-unqualified 승격된 산술 타입 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, 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 모두 prvalue여야 하며, 다음 조건 중 하나를 만족해야 합니다:

  • 두 피연산자 모두 산술 타입이나 비한정 열거형 타입을 가집니다. 이 경우, usual arithmetic conversions 가 두 피연산자에 대해 수행됩니다.
  • 정확히 하나의 피연산자만 정수형이나 비한정 열거형 타입을 가집니다. 이 경우, 해당 피연산자에 integral promotion이 적용됩니다.

이 섹션의 나머지 설명에서 "피연산자(들)", lhs rhs 는 변환되거나 승격된 피연산자(들)를 가리킵니다.

1) 내장 더하기 연산의 경우 다음 조건 중 하나를 만족해야 합니다:
  • 두 피연산자가 모두 산술 타입을 가져야 합니다. 이 경우 결과는 피연산자들의 합입니다.
  • 한 피연산자가 완전히 정의된 객체 타입에 대한 포인터이고, 다른 피연산자가 정수 타입을 가져야 합니다. 이 경우 정수 값이 포인터에 더해집니다 (참조: pointer arithmetic ).
2) 내장 빼기 연산의 경우 다음 조건 중 하나가 충족되어야 합니다:
  • 두 피연산자가 모두 산술 타입을 가져야 합니다. 이 경우 결과는 lhs 에서 rhs 를 뺀 차이입니다.
  • lhs 가 완전히 정의된 객체 타입에 대한 포인터이고, rhs 가 정수 타입을 가져야 합니다. 이 경우 정수 값이 포인터에서 감산됩니다( pointer arithmetic 참조).
  • 두 피연산자가 모두 동일한 완전히 정의된 객체 타입의 cv-qualified 또는 cv-unqualified 버전에 대한 포인터여야 합니다. 이 경우 rhs lhs 에서 감산됩니다( pointer arithmetic 참조).

두 피연산자가 모두 부동 소수점 타입이고, 해당 타입이 IEEE 부동 소수점 연산을 지원하는 경우(참조: std::numeric_limits::is_iec559 ):

  • 피연산자 중 하나가 NaN이면 결과는 NaN입니다.
  • 무한대에서 무한대를 빼면 NaN이 되며, FE_INVALID 가 발생합니다.
  • 무한대와 음의 무한대를 더하면 NaN이 되며, FE_INVALID 가 발생합니다.

포인터 연산

정수형을 가진 표현식 J 가 포인터 타입의 표현식 P 에 더해지거나 빼질 때, 결과는 P 의 타입을 가집니다.

  • 만약 P null 포인터 값 으로 평가되고 J 0 으로 평가되면, 결과는 null 포인터 값입니다.
  • 그렇지 않고 P n 개의 요소를 가진 배열 객체 x i 번째 요소를 가리키고, J 의 값이 j 로 주어지면, P 는 다음과 같이 더하거나 뺍니다:
  • 표현식 P + J J + P
  • i+j 번째 요소를 가리키며, 이는 i + j [ 0 , n ) 범위 내에 있을 경우에 해당합니다. 그리고
  • i + j n 인 경우, 마지막 요소의 끝을 지나는 포인터입니다.
  • 표현식 P - J
  • i-j 번째 요소를 가리키며, 이는 i - j [ 0 , n ) 범위 내에 있을 경우에 해당합니다. 그리고
  • i - j n 인 경우, 마지막 요소의 끝을 지나는 포인터입니다.
  • 다른 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 입니다.
  • 만약 i − j std::ptrdiff_t 로 표현 불가능할 경우, 동작은 정의되지 않습니다.
  • 그렇지 않고, P Q 가 동일한 완전 객체, 기본 클래스 하위 객체 또는 멤버 하위 객체를 가리키는 경우, 결과는 0 입니다.
  • 그렇지 않은 경우, 동작은 정의되지 않습니다.

이러한 포인터 산술 연산자를 통해 포인터는 LegacyRandomAccessIterator 요구 사항을 충족할 수 있습니다.

덧셈과 뺄셈의 경우, P 또는 Q 가 "(cv 한정자가 있을 수 있는) T 에 대한 포인터" 타입을 가지고, T 와 배열 요소 타입이 유사(similar) 하지 않을 경우, 그 동작은 정의되지 않습니다:

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"는 unsigned int가 아닌 int를 가리킵니다

오버로드

사용자 정의 연산자에 대한 오버로드 해결 에서, 모든 승격된 산술 타입 쌍 L R , 그리고 모든 객체 타입 T 에 대해 다음 함수 시그니처들이 오버로드 해결에 참여합니다:

LR 연산자 + ( L, R )
LR 연산자 - ( L, R )
T * 연산자 + ( T * , std:: ptrdiff_t )
T * 연산자 + ( std:: ptrdiff_t , T * )
T * 연산자 - ( T * , std:: ptrdiff_t )
std:: ptrdiff_t 연산자 - ( T * , T * )

여기서 LR usual arithmetic conversions 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)
**참고:** 원본 텍스트에 번역이 필요한 내용이 없으며, 모든 요소가 HTML 태그, 코드 태그, C++ 용어로 구성되어 있어 번역이 적용되지 않았습니다.
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이 됩니다.
  • 무한대와 0을 곱하면 NaN이 되고 FE_INVALID 가 발생합니다.
2) 내장 나눗셈의 결과는 lhs rhs 로 나눈 값입니다. 만약 rhs 가 0이면, 동작은 정의되지 않습니다.
두 피연산자가 모두 정수형을 가지면, 결과는 대수적 몫입니다(정수 나눗셈 수행): 몫은 0 방향으로 잘림(소수 부분은 버려짐).
두 피연산자가 모두 부동 소수점 타입이고, 해당 타입이 IEEE 부동 소수점 연산을 지원하는 경우( std::numeric_limits::is_iec559 참조):
  • 한 피연산자가 NaN인 경우, 결과는 NaN입니다.
  • ​0이 아닌 숫자를 ±0.0으로 나누면 올바른 부호의 무한대가 생성되고 FE_DIVBYZERO 가 발생합니다.
  • 0.0을 0.0으로 나누면 NaN이 생성되고 FE_INVALID 가 발생합니다.
3) 내장 나머지 연산의 결과는 lhs rhs 로 정수 나눗셈한 나머지입니다. rhs 가 0인 경우, 동작은 정의되지 않습니다.
만약 a / b 가 결과 타입으로 표현 가능하다면, ( a / b ) * b + a % b == a 입니다.
만약 a / b 가 결과 타입으로 표현 불가능할 경우, a / b a % b 모두의 동작은 정의되지 않음 (이는 INT_MIN % - 1 가 2의 보수 시스템에서 정의되지 않음을 의미함).

참고: CWG issue 614 가 해결되기 전까지 ( N2757 ), 이항 연산자 %의 한쪽 또는 양쪽 피연산자가 음수인 경우 나머지의 부호는 구현에 따라 정의되었습니다. 이는 정수 나눗셈의 반올림 방향에 의존하기 때문입니다. std::div 함수는 이러한 경우에 잘 정의된 동작을 제공했습니다.

참고: 부동 소수점 나머지 연산에 대해서는 std::remainder std::fmod 를 참조하십시오.

오버로드

사용자 정의 연산자에 대한 오버로드 해결 에서, 승격된 산술 타입 쌍 LA RA 에 대해, 그리고 승격된 정수 타입 쌍 LI RI 에 대해 다음 함수 시그니처들이 오버로드 해결에 참여합니다:

LRA 연산자 * ( LA, RA )
LRA 연산자 / ( LA, RA )
LRI 연산자 % ( 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)
**참고:** C++ 비트 연산자 표기법은 원래 형태를 유지해야 하므로 모든 연산자 기호(~, &, |, ^)와 변수명(lhs, rhs)은 번역하지 않고 그대로 유지했습니다. 숫자 표시(1)-(4)도 원본을 유지했습니다.
1) 비트 NOT 연산.
2) 비트 AND 연산.
3) 비트 OR 연산.
4) 비트별 XOR.

비트 NOT 연산자는 모든 이항 산술 연산자보다 우선순위 가 더 높습니다. 오른쪽에서 왼쪽으로 결합합니다:

~a - b; // (~a) - b와 동일하며, ~(a - b)가 아님
~c * d; // (~c) * d와 동일하며, ~(c * d)가 아님
~-e; // ~(-e)와 동일함

~ 다음에 type name 또는 decltype specifier (since C++11) 이 올 때 문법적 모호성이 존재합니다: 이는 operator~일 수도 있고 destructor 식별자의 시작일 수도 있습니다. 이 모호성은 ~ 를 operator~로 해석함으로써 해결됩니다. ~ 는 operator~를 형성하는 것이 구문적으로 유효하지 않은 위치에서만 destructor 식별자를 시작할 수 있습니다.

다른 모든 비트 논리 연산자는 다른 모든 이항 산술 연산자보다 우선순위 가 낮습니다. 비트 AND는 비트 XOR보다 우선순위가 높으며, 비트 XOR은 비트 OR보다 우선순위가 높습니다. 이들은 왼쪽에서 오른쪽으로 결합합니다:

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)와 동일

내장 비트 논리 연산자

내장 비트 NOT 연산자의 경우, rhs 는 정수형 또는 비한정 열거형의 prvalue여야 하며, rhs 에 대해 정수 승격이 수행됩니다. 다른 내장 비트 논리 연산자의 경우, 두 피연산자 모두 정수형 또는 비한정 열거형이어야 하며, 두 피연산자에 대해 일반 산술 변환 이 수행됩니다.

이 섹션의 나머지 설명에서 "피연산자(들)", lhs rhs 는 변환되거나 승격된 피연산자(들)를 가리킵니다.

1) 피연산자를 x 로, 내장 비트 NOT 연산의 결과를 r 로 가정합니다. x 의 2진 표현에서 각 계수 x_i 에 대해, r 의 2진 표현에서 대응하는 계수 r_i 1 입니다 (만약 x_i 0 인 경우). 그렇지 않으면 0 입니다.
  • 다른 말로, 결과는 피연산자의 1의 보수입니다 (피연산자와 결과가 부호 없는 것으로 간주되는 경우).
결과의 타입 r 는 피연산자 x 의 타입입니다.
2-4) 피연산자를 각각 x y 로, 내장 이진 비트 논리 연산의 결과를 r 로 가정합니다. x y 의 2진 표현의 각 계수 쌍 x_i y_i 에 대해, r 의 2진 표현에 대응하는 계수 r_i
2) 1 만약 x_i y_i 모두 1 인 경우, 그렇지 않으면 0 입니다.
3) 1 x_i y_i 중 적어도 하나가 1 이면 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 usual arithmetic conversions 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)
**참고:** 주어진 텍스트에는 HTML 태그와 속성, 코드 태그 내의 C++ 연산자(`<<`, `>>`) 및 변수명(`lhs`, `rhs`) 외에 번역이 필요한 일반 텍스트가 없습니다. 따라서 원본 형식과 내용이 그대로 유지되었습니다.
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)가 아님

내장 비트 시프트 연산자

내장 비트 시프트 연산자의 경우, 두 피연산자는 모두 정수형 또는 비한정 열거형의 prvalue여야 합니다. 두 피연산자에 대해 정수 승격이 수행됩니다.

이 섹션의 나머지 설명에서 "피연산자(들)", a , b , lhs rhs 는 변환되거나 승격된 피연산자(들)를 가리킵니다.

rhs 의 값이 음수이거나 lhs 의 비트 수보다 작지 않은 경우, 동작은 정의되지 않습니다.

부호 없는 a 의 경우, a << b 의 값은 a * 2 b
의 값을 반환 타입의 비트 수 N에 대한 2 N
모듈로로 환산한 값입니다(즉, 비트 단위 왼쪽 시프트가 수행되고 대상 타입에서 벗어난 비트들은 버려집니다).

부호 있는 비음수 a 의 경우, a * 2 b
가 반환 타입의 부호 없는 버전으로 표현 가능하다면, 그 값을 부호 있는 타입으로 변환 한 값이 a << b 의 값입니다(이로 인해 INT_MIN 1 << 31 로 생성하는 것이合法입니다). 그렇지 않으면 동작은 정의되지 않습니다.

음수 a 의 경우, a << b 의 동작은 정의되지 않습니다.

부호 없는 a 와 부호 있는 비음수 a 의 경우, a >> b 의 값은 a/2 b
의 정수 부분입니다.

음수 a 의 경우, a >> b 의 값은 구현에 따라 정의됩니다(대부분의 구현에서는 산술 오른쪽 시프트를 수행하여 결과가 음수로 유지됩니다).

(C++20 이전)

a << b 의 값은 a * 2 b
와 합동인 유일한 값으로, 반환 타입의 비트 수 N에 대한 2 N
모듈로로 환산됩니다(즉, 비트 단위 왼쪽 시프트가 수행되고 대상 타입에서 벗어난 비트들은 버려집니다).

a >> b 의 값은 a/2 b
로, 음의 무한대 방향으로 반올림됩니다(다시 말해, 부호 있는 a 에 대한 오른쪽 시프트는 산술 오른쪽 시프트입니다).

(C++20 이후)

결과의 타입은 lhs 의 타입과 동일합니다.

오버로드

사용자 정의 연산자에 대한 오버로드 해결 에서, 승격된 정수 타입 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" // unsigned에서 오버플로우 발생
                 "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> 의 public member function)
복소수에 단항 연산자 적용
(function template)
valarray의 각 요소에 단항 산술 연산자 적용
( std::valarray<T> 의 public member function)

덧셈 연산자

time_point를 포함하는 덧셈 및 뺄셈 연산 수행
(함수 템플릿)
duration을 인자로 사용하는 산술 연산 구현
(함수 템플릿)
year_month_day 와 일정 년수 또는 월수를 더하거나 뺌
(함수)
두 문자열, 문자열과 char , 또는 문자열과 string_view 를 연결함
(함수 템플릿)
반복자를 진행시키거나 감소시킴
( std::reverse_iterator<Iter> 의 public 멤버 함수)
반복자를 진행시키거나 감소시킴
( std::move_iterator<Iter> 의 public 멤버 함수)
두 복소수 값 또는 복소수와 스칼라에 대한 복소수 산술 연산 수행
(함수 템플릿)
두 valarray의 각 요소에 이항 연산자를 적용하거나 valarray와 값에 적용
(함수 템플릿)

곱셈 연산자

duration을 인자로 하는 산술 연산 구현
(함수 템플릿)
두 복소수 값 또는 복소수와 스칼라에 대한 복소수 산술 연산 수행
(함수 템플릿)
두 valarray의 각 요소 또는 valarray와 값에 이항 연산자 적용
(함수 템플릿)

비트 논리 연산자

이진 AND, OR, XOR 및 NOT 연산 수행
( std::bitset<N> 의 public member function)
bitset에 대한 이진 논리 연산 수행
(function template)
valarray의 각 요소에 단항 산술 연산자 적용
( std::valarray<T> 의 public member function)
두 valarray의 각 요소에 이항 연산자 적용, 또는 valarray와 값에 적용
(function template)

비트 시프트 연산자

두 valarray의 각 요소에 이항 연산자를 적용하거나, valarray와 값에 적용
(함수 템플릿)
이진 왼쪽 시프트와 오른쪽 시프트를 수행
( std::bitset<N> 의 public 멤버 함수)

스트림 삽입/추출 연산자

표준 라이브러리 전체에서, 비트 시프트 연산자는 일반적으로 I/O 스트림( std:: ios_base & 또는 이를 상속받은 클래스들 중 하나)을 좌측 피연산자 및 반환 타입으로 오버로드됩니다. 이러한 연산자는 스트림 삽입 스트림 추출 연산자로 알려져 있습니다:

형식화된 데이터를 추출합니다
( std::basic_istream<CharT,Traits> 의 public member function)
문자와 문자 배열을 추출합니다
(function template)
형식화된 데이터를 삽입합니다
( std::basic_ostream<CharT,Traits> 의 public member function)
문자 데이터를 삽입하거나 rvalue 스트림에 삽입합니다
(function template)
복소수를 직렬화 및 역직렬화합니다
(function template)
bitset의 스트림 입력 및 출력을 수행합니다
(function template)
문자열에 대한 스트림 입력 및 출력을 수행합니다
(function template)
의사 난수 엔진에 대한 스트림 입력 및 출력을 수행합니다
(function template)
의사 난수 분포에 대한 스트림 입력 및 출력을 수행합니다
(function template)

결함 보고서

다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
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 산술 연산자가 피연산자로 lvalue를 허용함 일부 피연산자는 rvalue여야 함
CWG 1865 C++98 CWG 이슈 1504 의 해결이 배열 요소에 대한
포인터 연산 동작을 가리키는 타입과 배열 요소
타입이 최상위 수준이 아닌 곳에서 다른 cv-한정자를
가질 경우 정의되지 않도록 만듦
명확히 정의됨
CWG 1971 C++98 ~ 의 모호성 해결 규칙이 ~X ( 0 ) 와 같은
경우에 적용되는지 불명확했음
해당 규칙이 이러한 경우에 적용됨
CWG 2419 C++98 비-배열 객체에 대한 포인터는 & 연산자로
얻은 경우에만 크기 1인 배열의 첫 번째 요소에
대한 포인터로 취급됨
모든 비-배열 객체에 대한
포인터에 적용됨
CWG 2626 C++98 내장 operator~ 의 결과가 적절한 정의 없이
단순히 '1의 보수'로 기술됨
결과가 기수-2 표현을
기준으로 명시됨
CWG 2724 C++20 산술 우측 시프트의 반올림 방향이 불명확했음 명확히 정의됨
CWG 2853 C++98 객체 끝을 지난 포인터에
정수를 더하거나 뺄 수 없었음
가능함

참고 항목

연산자 우선순위

연산자 오버로딩

일반 연산자
assignment increment
decrement
arithmetic logical comparison member
access
other

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-style cast static_cast , const_cast , 그리고 reinterpret_cast 의 혼합으로 타입 변환을 수행
new 동적 저장 기간을 가진 객체를 생성
delete new 표현식으로 생성된 객체를 파괴하고 획득한 메모리 영역을 해제
sizeof 타입의 크기를 조회
sizeof... pack 의 크기를 조회 (C++11부터)
typeid 타입의 정보를 조회
noexcept 표현식이 예외를 발생시킬 수 있는지 확인 (C++11부터)
alignof 타입의 정렬 요구사항을 조회 (C++11부터)

C 문서 for Arithmetic operators