[C++/ETC] C++ 연산자 우선순위
참고(영어) ( : C++ Operator Precedence )
목차
1. 연산자 우선순위 표
2. 연산 방향
3. 우선순위를 고려해야하는 이유
4. 함께 볼만한 글
1. 연산자 우선순위 표
우선순위 | 연산자 | 설명 | 방향 |
1 | :: | 범위(Scope) 접근 | ⇨ 방향 |
2 | a++ a-- | 후위 증감 연산자 | |
type() type{} | 형변환 | ||
a() | 함수 호출 | ||
a[] | (배열) 접근 연산자 | ||
. -> | (멤버) 접근 연산자 | ||
3 | ++a --a | 전위 증감 연산자 | ⇦ 방향 |
+a -a | 부호 연산자 | ||
! ~ | 논리, 비트 not 연산자 | ||
(type) | C 스타일 형변환 | ||
* | 참조 연산자 | ||
&a | 주소 연산자 | ||
sizeof | 크기 연산자 | ||
co_await | |||
new new[] | 동적할당 연산자 | ||
delete delete[] | 할당해제 연산자 | ||
4 | .* ->* | 포인터 (멤버) 접근 연산자 | ⇨ 방향 |
5 | a*b a/b a%b | 산술 연산자 | |
6 | a+b a-b | 산술 연산자 | |
7 | << >> | 비트 시프트 연산자 | |
8 | <=> | 비교 연산자 | |
9 | < <= > >= | 비교 연산자 | |
10 | == != | 비교 연산자 | |
11 | a&b | 비트 AND 연산자 | |
12 | a^b | 비트 XOR 연산자 | |
13 | a|b | 비트 OR 연산자 | |
14 | && | 논리 AND 연산자 | |
15 | || | 논리 OR 연산자 | |
16 | a?b:c | 삼항 연산자 | ⇦ 방향 |
throw | |||
co_yield | |||
= | 대입 연산자 | ||
+= -= | 복합 대입 연산자 | ||
*= /= %= | 복합 대입 연산자 | ||
<<= >>= | 복합 대입 연산자 | ||
&= ^= |= | 복합 대입 연산자 | ||
17 | , | ⇨ 방향 |
2. 연산 방향
연산 방향은 피연산자(수의 덧셈(+)이라면 숫자)를 기준으로 표현합니다.
즉, + 연산의 ⇨ 방향이라는 의미는 1+2+3에서 "(1과 2를 더한 결과)과 3을 더한 결과"이 됩니다.
대입 연산의 경우 ⇦ 방향의 의미가 a = b = 3 에서 "(3을 b에 대입한 결과)를 a에 대입한 결과"가 됩니다.
우리가 기본적으로 사칙연산할 때 왼쪽부터 순서대로 계산하기 때문에 ( ex. 3-5+4 == 2 )
사칙연산처럼 모두 왼쪽에서 오른쪽이면 편하지 않을까 생각할 수 있는데, 연산 방향은 필요합니다.
먼저 대입 연산만 봐도 연산 방향이 다른 것을 알 수 있습니다. ( ex. a = 3+5 // 는 3+5 결과를 a에 대입 )
// 예를 들어
int a;
a = 1+2+3; // 이 코드를
1+2+3 = a; // 처럼 사용하면 안될까 생각할수도 있습니다
또한 연산 방향을 알면 해당 연산을 어떻게 사용할지 알 수 있습니다.
sizeof 와 같은 연산은 변수의 할당된 크기를 구하며 피연산자를 하나만 필요로 합니다.
(산술 연산자와 대입 연산자는 피연산자가 좌우에 각각 두개입니다)
sizeof 연산의 연산방향은 ⇦ 방향으로 따라서 피연산자가 오른쪽에 위치해야합니다.
마찬가지로 주소 연산자와 전위 증감 연산자도 ⇦ 방향으로 따라서 피연산자가 오른쪽에 위치해야합니다.
배열 접근과 함수 호출 연산은 ⇨ 방향으로 피연산자(배열 이름 또는 첫 주소, 함수 이름)가 왼쪽에 위치합니다.
프로그래머가 원하는 상황에 따라서 원하는 방향대로 작동해주기를 바랄수도 있습니다.
하지만 프로그래밍 언어는 중의적인 표현을 원하지 않습니다.
이와 관련해서는 프로그래밍 언어론의 모호성(ambiguous)에 대해서 읽어보시면 좋을 것 같습니다.
3. 우선순위를 고려해야하는 이유
가장 대표적으로 포인터의 멤버 접근을 예로 들 수 있습니다.
struct a {
int i;
};
int main() {
a var1{3};
a* var2{ &var1 };
cout << *var2.i; // 의도한 것은 (*var).i
}
위의 예시는 오류가 발생하는 코드입니다. 이는 멤버 접근 연산자의 우선 순위(2)가 포인터 참조 연산자 우선 순위(3)보다 우선순위가 빠르기 때문입니다. 몰론 아주 초보적인 예시이고, 포인터 참조를 위해 -> 와 같은 포인터 멤버 참조 연산을 제공하기 때문에 여전히 우선순위를 따지는 상황이 있을지 고민될 수 있습니다.
사실 위에서 2에서 얘기한 것처럼 간단한 대입연산만 해도 연산자의 우선 순위 때문에 편하게 사용할 수 있습니다.
a = 1+2+3; // 대입 연산이 우선 순위가 빨랐다면 a=1 이 먼저 이루어진다.
대입 연산이 우선 순위가 빨랐다면 (a=1)+2+3 처럼 표현할 수 있으며 이는 a=1+2+3 과 다릅니다.
4. 함께 볼만한 글
- 연산자 오버라이드
- 프로그래밍 언어론 - 모호성