C 연산자 우선순위

C 연산자 우선순위 (C Operator Precedence)

어떤 표현식이 어떻게 묶이는지는 연산자 우선순위와 결합 규칙이 정해요. 예를 들어 *p++(*p)++로 해석되는지 *(p++)로 해석되는지가 여기서 갈리죠. 이 페이지에서 C 연산자의 우선순위와 결합 규칙을 표로 정리해 볼게요.

출처: cppreference

본문

다음 표는 C 연산자의 우선순위와 결합 규칙(associativity)을 나열해요. 연산자는 위에서 아래로 갈수록 우선순위가 낮아져요.

우선순위 연산자 설명 결합 규칙
1 ++ -- 접미사/후위 증가·감소 왼쪽→오른쪽
() 함수 호출
[] 배열 첨자
. 구조체·공용체 멤버 접근
-> 포인터를 통한 구조체·공용체 멤버 접근
(type){list} 복합 리터럴 (C99)
2 ++ -- 접두사/전위 증가·감소 [^1] 오른쪽→왼쪽
+ - 단항 더하기·빼기
! ~ 논리 NOT·비트 NOT
(type) 캐스트
* 간접(역참조)
& 주소 연산
sizeof 크기 연산 [^2]
_Alignof 정렬 요구사항 (C11)
3 * / % 곱셈·나눗셈·나머지 왼쪽→오른쪽
4 + - 덧셈·뺄셈
5 << >> 비트 왼쪽·오른쪽 시프트
6 < <= 관계 연산자 < 및 ≤
> >= 관계 연산자 > 및 ≥
7 == != 관계 연산자 = 및 ≠
8 & 비트 AND
9 ^ 비트 XOR (배타적 or)
10 | 비트 OR (포함적 or)
11 && 논리 AND
12 || 논리 OR
13 ?: 삼항 조건 [^3] 오른쪽→왼쪽
14 [^4] = 단순 할당
+= -= 합·차에 의한 할당
*= /= %= 곱·몫·나머지에 의한 할당
<<= >>= 비트 왼쪽·오른쪽 시프트에 의한 할당
&= ^= |= 비트 AND·XOR·OR에 의한 할당
15 , 콤마 왼쪽→오른쪽

[^1]: 전위 ++--의 피연산자는 타입 캐스트일 수 없어요. 이 규칙은 문법상으로 어떤 표현식들을 금지하는데, 어차피 그 표현식들은 의미상으로도 유효하지 않아요. 일부 컴파일러는 이 규칙을 무시하고 유효하지 않음을 의미적으로 검출해요.

[^2]: sizeof의 피연산자는 타입 캐스트일 수 없어요: sizeof(int) * p 표현식은 (sizeof(int)) * p로 명확히 해석되지, sizeof((int) * p)로는 해석되지 않아요.

[^3]: 조건 연산자의 중간 표현식(?: 사이)은 마치 괄호로 감싼 것처럼 해석돼요. 즉 ?:에 대한 상대적 우선순위는 무시돼요.

[^4]: 할당 연산자의 왼쪽 피연산자는 단항(레벨 2, 비-캐스트) 표현식이어야 해요. 이 규칙은 문법상으로 어떤 표현식들을 금지하는데, 어차피 그 표현식들은 의미상으로도 유효하지 않아요. 많은 컴파일러는 이 규칙을 무시하고 유효하지 않음을 의미적으로 검출해요. 예를 들어 e = a < d ? a++ : a = d는 이 규칙 때문에 파싱될 수 없는 표현식이에요. 하지만 많은 컴파일러는 이 규칙을 무시하고 e = (((a < d) ? (a++) : a) = d)로 파싱한 다음, 의미상 유효하지 않으므로 오류를 내요.

표현식을 파싱할 때, 어떤 행에 나열된 연산자는 그보다 아래 행에 있는 어떤 연산자보다 자기 인자에 더 강하게(마치 괄호로 감싼 것처럼) 결합돼요. 예를 들어 *p++*(p++)로 해석되지, (*p)++로 해석되지 않아요.

같은 셀에 있는 연산자(한 셀에 여러 행의 연산자가 나열될 수 있어요)는 같은 우선순위로, 주어진 방향으로 평가돼요. 예를 들어 a = b = c는 오른쪽→왼쪽 결합 때문에 a = (b = c)로 해석되지, (a = b) = c로 해석되지 않아요.

참고 사항 (Notes)

우선순위와 결합 규칙은 평가 순서(order of evaluation)와는 독립적인 개념이에요.

표준 자체는 우선순위 레벨을 명시하지 않아요. 그것들은 문법에서 파생돼요.

C++에서는 조건 연산자가 할당 연산자와 같은 우선순위를 가지며, 전위 ++·--와 할당 연산자는 피연산자에 대한 제약이 없어요.

결합 규칙 명시는 단항 연산자에는 중복되고 완전성을 위해서만 보여져요: 단항 전위 연산자는 항상 오른쪽→왼쪽으로 결합하고(sizeof ++*psizeof(++(*p))), 단항 후위 연산자는 항상 왼쪽→오른쪽으로 결합해요(a[1][2]++((a[1])[2])++). 결합 규칙은 단항 후위 연산자 그룹에 묶여 있음에도 멤버 접근 연산자에 의미가 있다는 점을 주의해요: a.b++(a.b)++로 해석되지 a.(b++)로 해석되지 않아요.

더 알아보기