Study About Computing/언어_Language

[C++/ETC] C++ 연산자 우선순위

gamgok 2022. 4. 19. 22:05

 

참고(영어) ( : 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. 함께 볼만한 글

  • 연산자 오버라이드
  • 프로그래밍 언어론 - 모호성