language/c

[C언어] 03. 수식과 연산자

렁치 2026. 7. 20. 17:30

프로그램이 하는 일의 대부분은 값을 계산하고 비교하고 조합하는 것이다. 이 모든 연산을 담당하는 것이 연산자다. 오늘은 산술·증감·관계·논리 연산자부터, 내가 자주 헷갈린 형변환과 연산 우선순위까지 정리했다.


1. 산술 연산자

기본 사칙연산과 나머지 연산이 있다.

연산자 의미 예 (a=7, b=2)
+ 덧셈 a + b → 9
- 뺄셈 a - b → 5
* 곱셈 a * b → 14
/ 나눗셈 a / b → 3 (정수 나눗셈)
% 나머지 a % b → 1

 

정수끼리의 나눗셈은 소수점이 버려진다
7 / 2 는 3.5가 아니라 3이다. 정수끼리 계산하면 결과도 정수가 되어 소수 이하가 잘리기 때문이다. 실수 결과가 필요하면 한쪽을 실수로 만들어야 한다(7.0 / 2 → 3.5). 이 함정은 뒤의 형변환에서 다시 다룬다.

2. 증감 연산자

++, --는 변수 값을 1 증가/감소시킨다. 붙는 위치에 따라 동작 시점이 달라지는 게 핵심이다.

  • 전위(prefix) ++x: 먼저 증가시킨 뒤 그 값을 사용한다.
  • 후위(postfix) x++: 먼저 현재 값을 사용한 뒤 증가시킨다.
int x = 5, y;
y = ++x;   // x를 6으로 만든 뒤 y에 대입 → x=6, y=6
x = 5;
y = x++;   // 현재 5를 y에 대입한 뒤 x 증가 → x=6, y=5

 

"증가가 먼저냐, 사용이 먼저냐"의 차이가 결과를 가른다. 처음엔 둘이 같은 줄 알았는데, y에 들어간 값이 6과 5로 갈리는 걸 직접 찍어보고서야 위치의 의미가 잡혔다.


3. 복합 대입 연산자

대입(=)과 다른 연산자를 결합한 것으로, x op= yx = x op y와 같다.

 

x += 3;   // x = x + 3
x *= y + 1;   // x = x * (y + 1)  ← 오른쪽 전체가 먼저 계산됨

 

x *= y + 1x = x*y + 1이 아니라 x = x*(y+1)이라는 점을 주의한다. 오른쪽 수식 전체가 먼저 계산된 뒤 대입된다.


4. 관계 연산자와 논리 연산자

관계 연산자는 두 값을 비교해 참(1) / 거짓(0)을 돌려준다.

 

C에는 원래 별도의 논리형이 없어서, 0은 거짓, 0이 아닌 값은 참으로 다룬다.

 

== 를 = 로 잘못 쓰지 않기
x == y 는 "같은가?"를 묻는 관계 연산이고, x = y 는 "y를 x에 대입"하는 대입 연산이다. 조건문에 if (x = y)라고 쓰면 비교가 아니라 대입이 일어나고, 그 대입 결과값으로 참거짓이 판정되어 의도와 전혀 다르게 동작한다. 가장 흔한 실수 중 하나다.

 

논리 연산자는 여러 조건을 조합한다. AND(&&), OR(||), NOT(!)이다.

 

(x >= 60) && (x < 100)    // x가 60 이상 100 미만
(x == 1) || (x == 2)      // x가 1 또는 2
(x != 0) && (x != 1)      // x가 0도 1도 아님

5. 조건 연산자와 콤마 연산자

조건 연산자(삼항 연산자)는 조건 ? 참일때값 : 거짓일때값 형태로, if문을 한 줄로 줄여준다.

max_value = (x > y) ? x : y;   // x가 크면 x, 아니면 y

 

콤마 연산자는 여러 수식을 왼쪽부터 차례로 계산한다(x++, y++).


6. 형변환 (Type Casting)

서로 다른 자료형이 섞이면 형이 변환된다.

자동 형변환 (묵시적)

  • 올림 변환: double f = 10; → f에 10.0 저장.
  • 내림 변환: int i = 3.14; → i에 3 저장(소수 이하 유실).
  • 수식 안에서: 서로 다른 타입이 섞이면 표현 범위가 큰 쪽으로 승급(promotion)된다. int + double은 int가 double로 올라가 결과도 double이 된다.

 

명시적 형변환 (캐스트 연산자)

(자료형) 수식 형태로 프로그래머가 직접 형을 지정한다.

 

(int)1.23456    // 1 로 변환
(double)x       // x를 double로

 

예제: 정수 나눗셈과 형변환
double f;
f = 3 / 2;          // 정수끼리 → 1, f는 1.000000
f = (double)3 / 2;  // 3을 double로 → 1.5, f는 1.500000

같은 3/2인데, 캐스트 하나로 결과가 1에서 1.5로 바뀐다. "언제 정수로 계산되고 언제 실수로 계산되는가"를 의식하는 게 중요하다.


7. 연산 우선순위

한 수식에 연산자가 여럿이면 우선순위에 따라 계산 순서가 정해지고, 같은 순위면 결합성(좌→우 또는 우→좌)을 따른다.

 

대략 "산술 → 관계 → 논리 → 대입" 순으로 우선순위가 낮아진다고 기억하면 큰 틀이 잡힌다. 헷갈릴 땐 괄호로 의도를 명확히 하는 게 가장 안전하다.


실습: 화씨를 섭씨로 변환

변환 공식은 섭씨 = 5/9 × (화씨 - 32)다.

 

여기서도 정수 나눗셈 함정
5 / 9 를 정수로 계산하면 0이 되어버려, 결과가 항상 0으로 나온다. 반드시 실수로 계산해야 한다.
double celsius = 5.0 / 9.0 * (fahrenheit - 32);

 


8. 수업 코드로 보는 초 → 시·분·초 변환

나눗셈과 나머지 연산을 함께 쓰는 좋은 예제다. 전체 초를 입력받아 시, 분, 초로 나눈다.

int iNo;
int iTemp;
int iSec;
int iHour;
int iMin;

printf("초 입력: ");
scanf("%d", &iNo);

iSec = iNo % 60;
iTemp = iNo / 60;
iHour = iTemp / 60;
iMin = iTemp - (iHour * 60);

printf("%d초는 %d시간, %d분, %d초입니다.\n", iNo, iHour, iMin, iSec);

 

입력 초 iSec iTemp(전체 분) iHour iMin
3661 1 61 1 1
85490 50 1424 23 44

 

이 문제는 %가 "남은 조각"을 구하고, /가 "큰 단위로 묶은 개수"를 구한다는 점을 보여준다. 단위 변환 문제는 대부분 이 두 연산을 번갈아 쓰면 풀린다.


오늘 느낀 점

  • 연산자가 종류만 많아 보였는데, 결국 "값을 계산·비교·조합한다"는 한 일의 갈래였다. 우선순위도 산술→관계→논리→대입의 큰 흐름으로 잡으니 외울 게 줄었다.
  • 정수 나눗셈 함정을 산술·형변환·실습에서 세 번이나 만났다. 같은 함정을 반복해 겪으니 이제는 나눗셈만 보면 타입을 의심하는 습관이 생겼다.
  • 우선순위를 다 외우려다 지쳤는데, "애매하면 괄호"라는 원칙이 외우기보다 훨씬 실용적이라는 걸 받아들였다.

한 걸음 더

  • 논리 연산자 &&||단축 평가(short-circuit)를 한다. A && B에서 A가 거짓이면 B는 아예 계산하지 않는다(어차피 결과가 거짓이니까). 이 성질을 이용해 (p != NULL) && (p->x > 0)처럼 "앞 조건이 참일 때만 뒤를 검사"하는 안전한 코드를 짤 수 있다.
  • 후위 증감(x++)이 "값을 쓴 뒤 증가"한다고 했는데, a[i++] = x;처럼 한 문장에서 같은 변수를 여러 번 증감하며 쓰면 동작이 정의되지 않는(undefined) 위험한 코드가 된다. 한 줄에 증감을 욕심내기보다 또박또박 나눠 쓰는 편이 안전하다.
  • 우선순위를 외우는 것보다 중요한 건 "애매하면 괄호"라는 원칙이다. 숙련된 개발자도 우선순위를 전부 외우진 않으며, 괄호로 의도를 드러낸 코드가 읽기에도 디버깅에도 유리하다.