본문으로 건너뛰기

산술·관계·논리 연산자와 우선순위

정보처리기사 목차프로그래밍 기초레슨 126 / 233

목차

연산자(operator)는 값을 셈하는 기호이고, 우선순위(precedence)는 한 식에 연산자가 여럿일 때 무엇부터 묶어 셈할지 정한 차례입니다. 왼쪽부터 차례로 셈하거나 &&·||의 오른쪽까지 늘 셈한다고 보면 출력이 틀리므로, 식을 계산 차례대로 하나씩 값으로 접어 가야 합니다. 아래 그림은 한 줄씩 실행하며 칸에 드는 값과, &&·||가 오른쪽을 셈하지 않는 줄을 보입니다.

9단계 중 1단계. 4번 줄 — a 칸에 7을 넣습니다. 이제 식의 계산 차례를 따라갑니다.

1산술·관계·논리 연산자

그림의 코드입니다.

#include <stdio.h>

int main(void) {
  int a = 7;
  int b = 0;
  int r = a + 2 * 3 % 4;
  int t = b > 0 && a % b == 1;
  int s = a > 3 || b == 1;
  printf("%d %d %d\n", r, t, s);
  return 0;
}
실행 결과
9 0 1
갈래연산자결과
산술+ - * / %수
관계< <= > >= == !=참이면 1, 거짓이면 0
논리&&(그리고) ||(또는) !(아님)참이면 1, 거짓이면 0

논리 연산자는 0을 거짓, 0이 아닌 값을 모두 참으로 보아 !5는 0, !0은 1입니다.

2우선순위와 결합 방향

연산자가 셈하는 값을 피연산자(operand)라 합니다. a + b에서는 a와 b입니다. !a·-a처럼 피연산자 하나에 붙는 연산자를 단항 연산자(unary operator)라 합니다.

위 칸일수록 먼저 묶어 셈합니다.

순위연산자
높음괄호 () · 단항 ! ++ -- 부호 - 캐스팅
* / %
+ -
시프트 << >>
관계 < <= > >=
같음 == !=
비트 & → ^ → |
논리 && → ||
조건 ? :
낮음대입 = += 등

같은 순위끼리 어느 쪽부터 묶는지를 결합 방향(associativity)이라 하고, 대부분은 왼쪽부터 묶습니다. 6번 줄은 *와 %가 같은 순위라 2 * 3을 먼저 셈하고, 그 값으로 6 % 4를, 마지막으로 7 + 2를 셈합니다. 단항·조건·대입만 오른쪽부터 묶습니다. a = b = 4;는 b에 4를 넣고 그 값을 a에 넣습니다. 시프트·비트 연산은 비트 연산과 2의 보수에서 셈합니다.

3단락 평가와 =·==

&&는 왼쪽이 0이면, ||는 왼쪽이 0이 아니면 결과가 정해져 오른쪽을 셈하지 않습니다. 이것을 단락 평가(short-circuit evaluation)라 하고, 자료에 따라 단축 평가라고도 부릅니다. 7번 줄은 b가 0이라 오른쪽 a % b를 셈하지 않아 0으로 나누지 않습니다. 오른쪽에 칸을 바꾸는 식이 있어도 실행되지 않습니다.

=는 오른쪽 값을 왼쪽 칸에 넣는 대입이고, 같은지 묻는 비교는 ==입니다. 절차형 SQL의 구조에서 본 PL/SQL과 기호가 뒤집혀 있습니다.

뜻C·Java·PythonPL/SQL
칸에 값을 넣음(대입)=:=
같은지 물음(비교)===

예제

나머지·몫·관계·논리가 한 식에 섞였습니다. 무엇이 찍힐까요?

#include <stdio.h>

int main(void) {
  int a = 10;
  int b = 3;
  int c = 0;
  int x = a % b * 2 + a / b;
  int y = !c && a - b * 3 > 0;
  int z = c == 0 || a / c > 1;
  printf("%d %d %d\n", x, y, z);
  return 0;
}
실행 결과 보기
실행 결과
5 1 1

x는 a % b(1)에 2를 곱한 2와 a / b(3)를 더해 5입니다. y는 !c가 1이고 a - b * 3이 1이라 1 > 0이 1, 둘 다 참이라 1입니다. z는 c == 0이 1이라 오른쪽 a / c를 셈하지 않고 1입니다.

같은 코드를 Java·Python으로

CJavaPython
논리 연산자&& || !&& || !and or not
비교의 결과1 · 0true · falseTrue · False
정수에 논리 연산5 && 3 → 1컴파일 오류5 and 3 → 3
몫 · 거듭제곱7 / 2 → 3 · 거듭제곱 연산자 없음C와 같음7 // 2 → 3 · 2 ** 3 → 8

Python의 and·or는 1·0이 아니라 마지막으로 본 값을 돌려줍니다. 0 or 5는 5입니다.

시험 포인트

  • 필기: 우선순위는 단항 → 산술(* / % → + -) → 시프트 → 관계 → 같음 → 비트 → 논리(&& → ||) → 조건 → 대입 차례입니다. 같은 순위는 왼쪽부터 묶고, 단항·조건·대입은 오른쪽부터 묶습니다. 관계·논리 연산의 결과는 1·0이고, &&·||는 단락 평가를 합니다. %는 정수의 나머지입니다. 대입 =·비교 ==는 PL/SQL의 :=·=와 뒤집힌 짝입니다.
  • 실기: 결과를 그대로 씁니다(연산자 우선순위 출제 주제). 건너뛴 오른쪽 식이 함정입니다. 이름으로는 단락 평가(Short-Circuit Evaluation)를 씁니다.

확인 문제

1. C 연산자를 우선순위가 높은 것부터 늘어놓은 것을 고르세요.

  • ① * → + → < → && → =
  • ② + → * → < → && → =
  • ③ * → + → && → < → =
  • ④ = → * → + → < → &&
정답

①입니다. 산술 안에서는 곱셈 쪽이 먼저이고, 산술 → 관계 → 논리 → 대입 차례입니다.

  • ② +는 *보다 늦습니다.
  • ③ 관계 <가 논리 &&보다 먼저입니다.
  • ④ 대입 =는 가장 늦습니다.

2. 위 예제에서 6번 줄만 int c = 2;로 바꿨습니다. 출력을 그대로 쓰세요. 답을 끝까지 쓴 뒤 정답을 펼치세요.

정답

받는 답:

5 0 1

x는 c와 상관없어 5 그대로입니다. y는 !c가 0이라 &&의 오른쪽을 셈하지 않고 0입니다. z는 c == 0이 0이라 이번에는 오른쪽 a / c > 1을 셈합니다. 10 / 2는 5라 참이 되어 1입니다.

  • 틀리는 꼴 y 1: !2를 1로 읽었습니다. 2는 참이라 !2는 0입니다.
  • 틀리는 꼴 z 0: 왼쪽이 거짓이면 ||가 바로 0을 낸다고 봤습니다. ||는 오른쪽까지 보아 하나라도 참이면 1입니다.

3. 다음 코드에서 식이 접히는 차례를 적은 표의 (가)~(라)를 채운 뒤, 출력을 그대로 쓰세요. 답을 끝까지 쓴 뒤 정답을 펼치세요.

#include <stdio.h>

int main(void) {
  int p = 3;
  int q = 8;
  int k = p + q * 2 > 18;
  int w = q % p == 2 && !k;
  printf("%d %d\n", k, w);
  return 0;
}
줄접히는 차례칸
6q * 2 → 16 · 3 + 16 → 19 · 19 > 18 → (가)k = (가)
7q % p → (나) · 그 값 == 2 → 1 · !k → (다)w = (라)
정답

(가) 1 · (나) 2 · (다) 0 · (라) 0

받는 답:

실행 결과
1 0

7번 줄은 &&의 왼쪽이 1이라 오른쪽 !k까지 셈합니다. k가 1이라 !k는 0이고, 1 && 0은 0입니다.

  • 틀리는 꼴 (가)에 19: 비교를 놓쳤습니다. > 18까지 셈해야 하고, 관계 연산의 결과는 1 또는 0입니다.
  • 틀리는 꼴 (라)에 1: !k를 k로 읽었습니다. !는 참과 거짓을 뒤집습니다.

4. 다음 코드의 출력을 그대로 쓰세요. 답을 끝까지 쓴 뒤 정답을 펼치세요.

#include <stdio.h>

int main(void) {
  int n = 17;
  int m = 5;
  int z = 0;
  char g = 'A';
  int p = n / m * m + n % m;
  int t = g + 2 == 'C' || n / z;
  int u = m > 9 && n / z;
  printf("%d %d %d\n", p, t, u);
  return 0;
}
정답

받는 답:

실행 결과
17 1 0

p는 몫 3에 5를 곱한 15와 나머지 2를 더해 17입니다. t는 +가 ==보다 먼저라 65 + 2 = 67이 'C'의 번호 67과 같아 1이고, ||의 오른쪽 n / z는 셈하지 않습니다. u는 m > 9가 0이라 오른쪽을 셈하지 않고 0입니다. 두 줄 모두 0으로 나누는 식에 닿지 않습니다.

  • 틀리는 꼴 오류로 멈춤: n / z를 셈한다고 봤습니다. 왼쪽만으로 결과가 정해져 오른쪽은 실행되지 않습니다.
  • 틀리는 꼴 p 2: n / m * m을 n / (m * m)으로 읽었습니다. /와 *는 같은 순위라 왼쪽부터 묶습니다.

5. 다음 (가)~(다)를 쓰세요. (가)는 한글 이름과 영문으로, (나)·(다)는 기호로 쓰세요. 답을 끝까지 쓴 뒤 정답을 펼치세요.

  • (가) &&의 왼쪽이 0이거나 ||의 왼쪽이 0이 아니면, 오른쪽은 셈하지 않고 결과를 내는 방식의 이름입니다.
  • (나) C에서 두 값이 같은지 묻는 연산자입니다.
  • (다) PL/SQL에서 변수에 값을 넣는 기호입니다.
정답

받는 답: (가) 단락 평가(Short-Circuit Evaluation) 또는 단축 평가 · (나) == · (다) :=

(가)의 실마리는 '왼쪽만 보고 결과를 정한다'입니다. (나)·(다)는 C와 PL/SQL에서 기호가 뒤집힌 짝입니다.

  • 틀리는 꼴 = — (나)에: C에서 =는 대입입니다. 같은지 묻는 것은 ==입니다.
  • 틀리는 꼴 = — (다)에: PL/SQL에서 =는 같은지 묻는 비교입니다. 값을 넣는 것은 :=입니다.

처음이라면: C 언어 과목(준비 중)의 '비교와 참 · 거짓' · '&& · || · !와 단락 평가' 레슨에서 같은 규칙을 처음부터 천천히 봅니다.

끝까지 내려오면 저절로 표시됩니다. 이 기기에만 저장합니다.

정보처리기사 목차로