연산자 우선순위 (Operator precedence)
• 4 + 2 * 3과 같은 복합 표현식의 파싱을 돕기 위해 모든 연산자에는 우선순위(Precedence) 레벨이 할당되어 있습니다.
• 더 높은 우선순위를 가진 연산자가 피연산자와 먼저 그룹화됩니다.

• 일반적으로 곱셈과 나눗셈(우선순위 레벨 5)은 덧셈과 뺄셈(우선순위 레벨 6)보다 높은 우선순위를 가집니다.
• 따라서 곱셈과 나눗셈은 덧셈과 뺄셈보다 먼저 피연산자와 그룹화됩니다.
• 즉, 4 + 2 * 3은 4 + (2 * 3)으로 그룹화됩니다.

연산자 결합 법칙 (Operator associativity)
• 동일한 우선순위를 가진 두 연산자가 표현식에서 서로 인접해 있는 경우,
• 연산자의 결합 법칙은 컴파일러에게 연산자를 왼쪽에서 오른쪽으로 평가할지,
• 오른쪽에서 왼쪽으로 평가할지를 알려줍니다. 

• 뺄셈은 우선순위 레벨 6이며, 레벨 6의 연산자들은 좌측 결합(Left-to-right) 법칙을 따릅니다.
• 따라서 이 식은 왼쪽에서 오른쪽으로 그룹화되어 (7 - 4) - 1이 됩니다.

연산자 우선순위(Precedence)와 결합성(Associativity) 표
• 아래 표는 연산자 우선순위/결합성을 빠르게 확인하기 위한 참고표입니다.
• 연산자 우선순위나 결합성에 대해 헷갈릴 때 다시 찾아볼 수 있도록 만들어졌습니다.

참고(Notes)
• 우선순위 레벨 1이 가장 높고, 레벨 17이 가장 낮습니다.
• 숫자가 작을수록 더 먼저 묶여서 계산됩니다.
• L→R: 좌측 결합
• R→L: 우측 결합

7dee8068f5dc3f8650bbd58b36857d691f4cd3


괄호를 사용하여 복합 표현식을 이해하기 쉽게 만들기

• 연산자와 우선순위 레벨이 너무 많아서 모두 기억하기 어렵습니다.

• 또한 복합 표현식이 어떻게 평가되는지 이해하기 위해 매번 연산자 표를 찾아보고 싶지는 않을 것입니다.

• 실수를 줄이고 우선순위 표를 참조하지 않고도 코드를 이해하기 쉽게 만들기 위해, 비자명한(non-trivial) 복합 표현식은 괄호로 묶어 의도를 명확히 하는 것이 좋습니다.


연산의 값 계산 (Value computation of operations)
• C++ 표준은 표현식에서 연산자를 실행하여 값을 생성하는 것을 값 계산(Value computation)이라는 용어로 표현합니다.
우선순위결합 법칙은 값 계산이 일어나는 순서를 결정합니다

피연산자의 평가 (Evaluation of operands)
• C++ 표준은 주로 평가(Evaluation)라는 용어를 피연산자의 평가를 지칭하는 데 사용합니다.
• 예를 들어, 표현식 a + b가 주어지면, a가 평가되어 어떤 값을 생성하고, b가 평가되어 어떤 값을 생성합니다. 이 값들은 operator+의 피연산자로 사용되어 값 계산에 쓰입니다.
• 비공식적으로 우리는 보통 "평가한다(evaluates)"라는 용어를 표현식의 피연산자뿐만 아니라 전체 표현식의 평가(값 계산)를 의미하는 데 사용합니다.

단항 산술 연산자 (Unary arithmetic operators)
• 단항 산술 연산자에는 더하기(+)와 빼기(-), 두 가지가 있습니다.
• 상기하자면, 단항 연산자(unary operators)는 하나의 피연산자(operand)만 취하는 연산자를 말합니다.

이항 산술 연산자 (Binary arithmetic operators)
• 5가지의 이항 산술 연산자가 있습니다.
• 이항 연산자(binary operators)는 왼쪽과 오른쪽, 두 개의 피연산자를 취하는 연산자입니다.
연산자 (Operator)기호 (Symbol)형태 (Form)연산 내용 (Operation)
덧셈 (Addition)+x + yx 더하기 y
뺄셈 (Subtraction)-x - yx 빼기 y
곱셈 (Multiplication)*x * yx 곱하기 y
나눗셈 (Division)/x / yx 나누기 y
나머지 (Remainder)%x % yx를 y로 나눈 나머지

부동 소수점 나눗셈 (floating point division)
• 만약 피연산자 중 하나(또는 둘 다)가 부동 소수점(floating point) 값이라면, 나눗셈 연산자는 부동 소수점 나눗셈을 수행합니다.
• 부동 소수점 나눗셈은 부동 소수점 값을 반환하며 소수점 이하 부분이 유지됩니다.
• 예를 들어, 7.0 / 4 = 1.75, 7 / 4.0 = 1.75, 7.0 / 4.0 = 1.75입니다.
• 모든 부동 소수점 산술 연산과 마찬가지로 반올림 오차(rounding errors)가 발생할 수 있습니다.

static_cast<>를 사용하여 정수끼리 부동 소수점 나눗셈하기
• 위의 내용은 의문을 제기합니다. 만약 두 개의 정수가 있고, 소수점 이하를 잃지 않고 나누고 싶다면 어떻게 해야 할까요?
• static_cast<>를 사용하여 정수를 부동 소수점 숫자로 변환하면, 정수 나눗셈 대신 부동 소수점 나눗셈을 수행할 수 있습니다.
• std::cout << "double / int = " << static_cast<double>(x) / y << '\n';

0과 0.0으로 나누기 (Dividing by 0 and 0.0)
• 정수 나눗셈에서 제수(나누는 수)가 0이면 미정의 동작(undefined behavior)을 유발합니다. 이는 수학적으로 정의되지 않기 때문입니다.
• 부동 소수점 값 0.0으로 나누는 결과는 구현 정의(implementation-defined)입니다 (즉, 컴파일러나 아키텍처에 따라 동작이 결정됩니다).
• IEEE754 부동 소수점 형식을 지원하는 아키텍처에서는 결과가 NaN(Not a Number) 또는 Inf(Infinity, 무한대)가 됩니다.
• 그 외의 아키텍처에서는 미정의 동작이 발생할 가능성이 큽니다.

산술 대입 연산자 (Arithmetic assignment operators)
• x = x + 4와 같은 구문을 작성하는 것은 매우 흔한 일이기 때문에, C++은 편의를 위해 5가지의 산술 대입 연산자(arithmetic assignment operators)를 제공합니다.
• x = x + 4 대신 x += 4라고 쓸 수 있습니다.
• x = x * y 대신 x *= y라고 쓸 수 있습니다.
연산자 (Operator)기호 (Symbol)형태 (Form)연산 내용 (Operation)
덧셈 대입 (Addition assignment)+=x += yx에 y를 더함 (x = x + y)
뺄셈 대입 (Subtraction assignment)-=x -= yx에서 y를 뺌 (x = x - y)
곱셈 대입 (Multiplication assignment)*=x *= yx에 y를 곱함 (x = x * y)
나눗셈 대입 (Division assignment)/=x /= yx를 y로 나눔 (x = x / y)
나머지 대입 (Remainder assignment)%=x %= yx에 (x를 y로 나눈) 나머지를 대입 (x = x % y)

값을 변경하는 연산자와 변경하지 않는 연산자 (Modifying and non-modifying operators)
• 피연산자 중 하나의 값을 변경할 수 있는 연산자를 비공식적으로 수정 연산자(modifying operator)라고 부릅니다.
• C++에서 대부분의 연산자는 비수정(non-modifying) 연산자입니다.
  1. 대입 연산자(Assignment operators): 표준 대입 연산자(=), 산술 대입 연산자(+=, -=, *=, /=, %=), 비트 대입 연산자(<<=, >>=, &=, |=, ^=)를 포함합니다.
  2. 증감 연산자(Increment and decrement operators): ++와 --입니다. 이에 대해서는 6.4 -- 증감 연산자와 부작용 강의에서 다룹니다.

나머지 연산자 (The remainder operator, operator%)
나머지 연산자(흔히 모듈로(modulo) 또는 모듈러스(modulus) 연산자라고도 부름)는 정수 나눗셈(integer division)을 수행한 후의 나머지를 반환하는 연산자입니다.
• 나머지 연산자는 정수 피연산자(integer operands) 에서만 동작합니다.

• 이 연산자는 어떤 숫자가 다른 숫자로 나누어 떨어지는지(evenly divisible) 확인할 때 가장 유용합니다(나누었을 때 나머지가 없다는 뜻).
• 만약 x % y의 결과가 0이라면, x는 y로 나누어 떨어진다는 것을 알 수 있습니다.
• 두 번째 숫자가 첫 번째 숫자보다 클 때, 두 번째 숫자는 첫 번째 숫자를 0번 나누게 되므로, 첫 번째 숫자가 그대로 나머지가 됩니다.
• 피연산자가 음수가 될 수 있는 경우, 나머지값도 음수가 될 수 있다는 점에 주의해야 합니다.
• 가능하다면 나눠떨어지는지 확인하기 위한 표현식을 작성할때 나머지 연산자(operator%)의 결과는 0과 비교하는 것을 선호하십시오.

거듭제곱 연산자는 어디 있나요? (Where’s the exponent operator?)
• 수학에서 거듭제곱을 나타내는 데 흔히 쓰이는 ^ 연산자는 C++에서 비트 XOR(Bitwise XOR) 연산입니다.
• C++에서 거듭제곱을 하려면 <cmath> 헤더를 포함하고 pow() 함수를 사용해야 합니다

• #include <cmath>
• double x{ std::pow(3.0, 4.0) }; // 3의 4승

• pow() 함수의 매개변수(그리고 반환값)는 double 타입이라는 점에 유의하세요.
• 부동 소수점 숫자의 반올림 오차(rounding errors)로 인해, 정수를 전달하더라도 pow()의 결과가 정확하지 않을 수 있습니다.

변수 증감 (Incrementing and decrementing variables)
• 변수의 값을 증가(1을 더함)시키거나 감소(1을 뺌)시키는 작업은 매우 빈번하게 발생하기 때문에, 이를 위한 전용 연산자가 존재합니다.

연산자기호형태작동 방식
전위 증가 (Prefix increment)++++xx를 증가시킨 후, x를 반환합니다.
전위 감소 (Prefix decrement)----xx를 감소시킨 후, x를 반환합니다.
후위 증가 (Postfix increment)++x++x를 복사하고, x를 증가시킨 뒤, 복사본을 반환합니다.
후위 감소 (Postfix decrement)--x--x를 복사하고, x를 감소시킨 뒤, 복사본을 반환합니다.

• 각 연산자에는 두 가지 버전이 있다는 점에 유의하세요.
• 연산자가 피연산자 앞에 오는 전위(prefix) 버전
• 연산자가 피연산자 뒤에 오는 후위(postfix) 버전

전위 증가 및 감소 (Prefix increment and decrement)
• 전위 증감 연산자는 매우 직관적입니다. 먼저 피연산자가 증가하거나 감소하고, 그 표현식은 피연산자의 값으로 평가(evaluate)됩니다.
• int y { ++x }; // x가 6으로 증가하고, x가 값 6으로 평가된 후, 6이 y에 할당됩니다.

후위 증가 및 감소 (Postfix increment and decrement)
• 후위 증감 연산자는 조금 더 까다롭습니다.
  1. 먼저 피연산자의 복사본을 만듭니다.
  2. 그 다음 피연산자(복사본이 아님)를 증가하거나 감소시킵니다.
  3. 마지막으로 (원래 값이 아닌) 복사본이 평가됩니다.
• int y { x++ }; // x가 6으로 증가하지만, 원래 x의 복사본이 값 5로 평가되어 5가 y에 할당됩니다.

쉼표 연산자 (The comma operator)
• 쉼표 연산자(comma operator) (,)는 단일 표현식(expression)이 허용되는 곳이라면 어디서든 다중 표현식을 평가할 수 있게 해줍니다.
• 쉼표 연산자는 왼쪽 피연산자(operand)를 평가한 다음, 오른쪽 피연산자를 평가하고, 오른쪽 피연산자의 결과를 반환합니다.
• 대부분의 프로그래머는 쉼표 연산자를 거의 사용하지 않지만, 유일한 예외로 for 루프(loops) 내부에서는 꽤 흔하게 사용됩니다.
• for 루프 내부를 제외하고는 쉼표 연산자 사용을 피하십시오.

조건 연산자 (The conditional operator)
• 조건 연산자(conditional operator, ?:)는 삼항 연산자(ternary operator), 즉 3개의 피연산자를 취하는 연산자입니다.
• ?: 연산자는 특정 유형의 if-else 문을 짧게 줄여 쓰는(shorthand) 방법을 제공합니다.
연산자기호형식의미
조건(삼항) 연산자 (Conditional/Ternary)?:c ? x : y조건 c가 참(true)이면 x를 평가하고, 그렇지 않으면 y를 평가합니다.

• ?: 연산자는 다음과 같은 형태를 취합니다.
• condition ? expression1 : expression2;
• condition이 참으로 평가되면 expression1이 평가되고, 그렇지 않으면 expression2가 평가됩니다.

조건 연산자는 표현식의 일부로 평가됩니다
• 조건 연산자는 표현식(expression)의 일부로 평가되므로, 표현식이 허용되는 곳이라면 어디든 사용할 수 있습니다.
• 조건 연산자의 피연산자가 상수 표현식(constant expression)인 경우, 조건 연산자 자체도 상수 표현식으로 사용할 수 있습니다.
• 복합 표현식(다른 연산자가 포함된 표현식)에서 사용될 때는 조건 연산 전체(피연산자 포함)를 괄호로 감싸십시오.
• 복잡한 표현식에서는 조건 연산자 사용을 피하십시오.

언제 조건 연산자를 사용해야 할까요? (So when should you use the conditional operator?)
• 두 값 중 하나로 객체를 초기화할 때
• 객체에 두 값 중 하나를 대입할 때
• 함수에 두 값 중 하나를 전달할 때
• 함수에서 두 값 중 하나를 반환할 때
• 두 값 중 하나를 출력할 때

관계 연산자(Relational operators)
• 관계 연산자(Relational operators)는 두 값을 비교할 때 사용하는 연산자입니다.
• C++에는 6가지 관계 연산자가 있습니다.

연산자기호형식동작
Greater than (보다 큼/초과)>x > yx가 y보다 크면 true, 아니면 false
Less than (보다 작음/미만)<x < yx가 y보다 작으면 true, 아니면 false
Greater than or equals (크거나 같음/이상)>=x >= yx가 y보다 크거나 같으면 true, 아니면 false
Less than or equals (작거나 같음/이하)<=x <= yx가 y보다 작거나 같으면 true, 아니면 false
Equality (동등/같음)==x == yx와 y가 같으면 true, 아니면 false
Inequality (부등/다르다)!=x != yx와 y가 같지 않으면 true, 아니면 false

• 관계 연산자를 사용하여 부동 소수점(floating point) 값을 비교하는 것은 위험할 수 있습니다.
• 이는 부동 소수점 값이 정밀하지 않으며(not precise), 피연산자의 작은 반올림 오차로 인해 예상보다 약간 작거나 클 수 있기 때문입니다.

부동 소수점과 관계 연산자
• 부동 소수점 값에 관계 연산자를 사용할 때, 대부분의 경우에는 신뢰할 수 있는 결과를 얻습니다.
• 하지만 피연산자가 거의 동일한 경우, 이 연산자들은 신뢰할 수 없는 것으로 간주해야 합니다.
• 특히 operator==와 operator!=를 사용하지 마십시오.

팁 (Tip)
• 부동 소수점 리터럴과 동일한 타입의 리터럴로 초기화된 변수를 비교하는 것은 안전합니다(유효 숫자가 정밀도 범위 내인 경우).
• 서로 다른 타입의 부동 소수점 리터럴을 비교하는 것은 일반적으로 안전하지 않습니다.

논리 연산자 (Logical operators)
• C++에는 3가지 논리 연산자가 있습니다.

OperatorSymbolExample UsageOperation
Logical NOT!!xx가 false이면 true, x가 true이면 false
Logical AND&&x && yx와 y가 둘 다 true이면 true, 아니면 false
Logical OR||x || yx 또는 y가 true이면(둘 중 하나 또는 둘 다) true, 아니면 false

논리 NOT (Logical NOT)
• 논리 NOT의 피연산자가 참(true)으로 평가되면, 논리 NOT은 거짓(false)으로 평가됩니다.
• 반대로 피연산자가 거짓으로 평가되면, 논리 NOT은 참으로 평가됩니다.
• 즉, 논리 NOT은 불리언 값을 참에서 거짓으로, 또는 그 반대로 뒤집습니다.
• 논리 NOT은 조건문에서 자주 사용됩니다.
• 주의해야 할 점은 논리 NOT 연산자의 우선순위(precedence)가 매우 높다는 것입니다.

논리 OR (Logical OR)
• 논리 OR 연산자는 두 조건 중 하나라도 참인지 테스트하는 데 사용됩니다.
• 왼쪽 피연산자가 참이거나, 오른쪽 피연산자가 참이거나, 둘 다 참인 경우 논리 OR 연산자는 참(true)을 반환합니다.
• 그렇지 않으면 거짓(false)을 반환합니다.
• 논리 OR 문은 여러 개를 연결할 수 있습니다. if (value == 0 || value == 1 || value == 2 || value == 3)

논리 AND (Logical AND)
• 논리 AND 연산자는 두 피연산자가 모두 참인지 테스트하는 데 사용됩니다.
• 두 피연산자가 모두 참이면 논리 AND는 참을 반환합니다.
• 그렇지 않으면 거짓을 반환합니다.
• 논리 OR와 마찬가지로 논리 AND 문도 여러 개를 연결할 수 있습니다. if (value > 10 && value < 20 && value != 16)

단락 평가 (Short circuit evaluation)
• 논리 AND가 참을 반환하려면 두 피연산자가 모두 참으로 평가되어야 합니다.
• 만약 왼쪽 피연산자가 거짓으로 평가되면, 논리 AND는 오른쪽 피연산자가 참인지 거짓인지와 상관없이 거짓을 반환해야 함을 알게 됩니다.
• 이 경우, 논리 AND 연산자는 오른쪽 피연산자를 평가하지 않고 즉시 거짓을 반환합니다!
• 이것을 단락 평가(short circuit evaluation)라고 하며, 주로 최적화를 목적으로 수행됩니다.

드모르간의 법칙 (De Morgan’s laws)
• 많은 프로그래머가 !(x && y)가 !x && !y와 같다고 생각하는 실수를 범합니다.
• 불행히도 논리 NOT은 그런 식으로 "분배"될 수 없습니다.

• 드모르간의 법칙(De Morgan’s laws)은 이러한 경우 논리 NOT이 어떻게 분배되어야 하는지 알려줍니다.

• !(x && y)는 !x || !y와 동등합니다.
• !(x || y)는 !x && !y와 동등합니다.

• 즉, 논리 NOT을 분배할 때는 논리 AND를 논리 OR로, 또는 그 반대로 뒤집어야 합니다!
• 이는 때때로 복잡한 표현식을 읽기 쉽게 만들 때 유용할 수 있습니다.

논리적 배타적 논리합(XOR) 연산자는 어디에 있나요?
• C++는 명시적인 논리 XOR 연산자를 제공하지 않습니다.

7dee8268f5dc3f8650bbd58b3680726c046c


• 그러나 bool 피연산자가 주어졌을 때 operator!= (같지 않음 연산자)는 논리 XOR와 동일한 결과를 생성합니다.

7dee8368f5dc3f8650bbd58b3683746d581d


• 따라서 논리 XOR는 다음과 같이 구현할 수 있습니다.
• if (a != b) ... // a XOR b, a와 b가 bool이라고 가정

• 이는 다음과 같이 여러 피연산자로 확장될 수 있습니다.
• if (a != b != c) ... // a XOR b XOR c, a, b, c가 bool이라고 가정
• 이 식은 피연산자(a, b, c) 중 홀수 개가 참(true)으로 평가될 때 true로 평가됩니다.

• 피연산자가 bool 타입이 아닌 경우, operator!=를 사용하여 논리 XOR를 구현하면 예상대로 작동하지 않습니다.