← C 강의 목록으로
🧱
기초 (Basic)
산술 · 비교 · 논리 · 형변환

4단원 — 연산자

값을 더하고, 비교하고, 논리적으로 결합하고, 형식을 바꾸는 것은 모두 **연산자**가 합니다. 이번 단원에서 다루는 연산자는 이후 모든 단원의 기초가 됩니다.

연산자++/--형변환
소요 시간
1~2시간
난이도
📊 완전 초보
선수 조건
🎯 기초 3단원
결과물
연산자 우선순위와 형변환을 이해한다

이 강의에서 배우는 것

  • 1산술/관계/논리/대입/증감/비트 연산자를 구분한다.
  • 2연산자 우선순위를 의식한다.
  • 3정수 나눗셈과 형 변환(타입 캐스팅)의 함정을 피한다.

왜 연산자에 별도 단원이 필요할까?

겉보기엔 익숙한 사칙연산처럼 보이지만, C에는 함정이 많습니다.

  • `7 / 2` 의 결과는 `3.5`가 아니라 `3` (정수 나눗셈).
  • `a == b` 와 `a = b` 는 완전히 다릅니다(비교 vs 대입).
  • `a++ + ++a` 같은 식은 결과가 컴파일러마다 다를 수 있습니다 (정의되지 않은 동작).

이 단원에서 "왜 결과가 이렇게 나오는지"를 미리 손에 익혀 둡니다.

핵심 개념

1) 산술 연산자

연산자의미
`+` `-` `*` `/`사칙연산`7 / 2` → 3 (정수)
`%`나머지 (정수형 전용)`7 % 2` → 1

**정수 / 정수 = 정수**, **실수 / 정수 = 실수**, **정수 / 실수 = 실수**.

2) 증감 연산자 (전위 / 후위)

c
int a = 5;
int b = a++;     // 후위: b는 5, a는 6
int c = ++a;     // 전위: a를 7로 만든 뒤 c에도 7

타이밍이 다르므로 한 줄에 같은 변수에 ++/-- 를 두 번 쓰면 위험합니다.

3) 관계 연산자

`==`, `!=`, `<`, `>`, `<=`, `>=`. 결과는 **0 또는 1**.

4) 논리 연산자와 단축 평가

연산자의미
`&&`AND. 좌측이 false면 우측은 평가하지 않음
`\\`OR. 좌측이 true면 우측은 평가하지 않음
`!`NOT
c
if (p != NULL && *p > 0) { /* p가 NULL이면 *p는 평가되지 않아 안전 */ }

5) 대입 연산자 가족

`=`, `+=`, `-=`, `*=`, `/=`, `%=`. `a += 3`은 `a = a + 3`과 같습니다.

6) 비트 연산자 (참고)

`&`, `|`, `^`, `~`, `<<`, `>>`. 임베디드/비트 플래그에서 자주 쓰입니다.

7) 형 변환(캐스팅)

c
int total = 95, count = 4;
double avg = (double)total / count;   // 23.75

`(double)`이 한쪽을 실수로 만들면 나머지도 실수로 자동 승격됩니다.

예제로 보기

예제 1 — `ex01_arith.c` : 사칙연산과 나머지

c
int a = 17, b = 5;

**실행 결과**

text
a = 17, b = 5
a + b = 22
a - b = 12
a * b = 85
a / b = 3  (정수 나눗셈)
a % b = 2  (나머지)
a / (double)b = 3.400

핵심: 같은 17/5인데 자료형 따라 결과(3 vs 3.4)가 달라집니다.

예제 2 — `ex02_increment.c` : 전위와 후위 차이

c
a = 5; b = a++;    // 후위
a = 5; b = ++a;    // 전위
a += 10; a *= 2;

**실행 결과**

text
후위: a=6, b=5
전위: a=6, b=6
a += 10 -> 16
a *= 2  -> 32

핵심: **후위는 "사용 후 증가"**, **전위는 "증가 후 사용"**. 결과적으로 a는 둘 다 6.

예제 3 — `ex03_logical.c` : 관계와 논리

c
int age = 25, has_license = 1;

**실행 결과**

text
a == b : 0
a != b : 1
a <  b : 1
a >= b : 0
성인이고 면허 있음: 1
미성년 또는 면허 없음: 0

핵심: 논리 연산 결과는 0/1이며, **0이 아닌 모든 값이 true** 로 취급됩니다.

예제 4 — `ex04_cast.c` : 캐스팅의 위력

c
int total = 95, count = 4;
double avg_wrong = total / count;          // 23
double avg_right = (double)total / count;  // 23.75

**실행 결과**

text
잘못된 평균(정수 나눗셈): 23.000
올바른 평균(캐스팅):       23.750
(int)3.99 = 3  (소수점 절단)

핵심: `int`로 캐스팅은 **반올림이 아니라 절단**(truncation).

다른 시각으로 보기 — 우선순위 한 줄 요약

text
높음 → 낮음
( ) [ ] -> .                       (괄호/접근)
! ++ -- (cast) sizeof &(주소)       (단항)
* / %                               (곱셈류)
+ -                                 (덧셈류)
< <= > >=                           (관계)
== !=                               (등가)
&& ||                               (논리)
?:                                  (삼항)
= += -= *= /=                       (대입)
,                                   (콤마)

기억하기 어려우면 **항상 괄호**를 씁시다. `a * b + c`는 `(a * b) + c`로 적어 두면 명확합니다.

자주 하는 실수

  1. **정수 나눗셈 함정**: 평균 계산에서 `sum / count`로 적었다가 소수점이 사라짐.
  2. **`==`와 `=` 혼동**: `if (a = 5)` 는 항상 참 + 부작용.
  3. **단축 평가 미인지**: `if (count != 0 && total / count > 10)` 처럼 가드 조건을 앞에 둬야 안전.
  4. **부호 있는/없는 비교**: `int -1`과 `unsigned 1`을 비교하면 -1이 아주 큰 양수로 해석됩니다.
  5. **`++`의 다중 사용**: `a = a++ + ++a;` 는 정의되지 않은 동작.

정리

  • 산술 연산은 자료형이 섞이면 결과 자료형이 결정된다(보통 더 큰 쪽으로 승격).
  • 정수/정수 나눗셈은 소수부가 잘린다. 평균 등에서는 캐스팅 필수.
  • 관계/논리 연산자의 결과는 0 또는 1이며, 0이 아닌 값은 true.
  • 단축 평가로 NULL 체크 같은 안전 가드를 만들 수 있다.
  • 모호하면 **괄호로 우선순위를 명시**.

직접 해 보기

bash
cd src
gcc -std=c11 -Wall -o ex01 ex01_arith.c     && ./ex01
gcc -std=c11 -Wall -o ex02 ex02_increment.c && ./ex02
gcc -std=c11 -Wall -o ex03 ex03_logical.c   && ./ex03
gcc -std=c11 -Wall -o ex04 ex04_cast.c      && ./ex04

응용:

  • `ex01`의 a, b 값을 음수로 바꾸고 `%`의 결과 부호를 관찰하세요.
  • `ex04`에서 `(int)(-3.99)`의 결과는 어떻게 될지 예측 후 확인.

💻 예제 (examples)

실제로 컴파일·실행해 결과를 확인할 수 있는 예제입니다.

ex01_arith.c사칙연산과 나머지
CODE
#include <stdio.h>

int main(void) {
    int a = 17, b = 5;

    printf("a = %d, b = %d\n", a, b);
    printf("a + b = %d\n", a + b);
    printf("a - b = %d\n", a - b);
    printf("a * b = %d\n", a * b);
    printf("a / b = %d  (정수 나눗셈)\n", a / b);
    printf("a %% b = %d  (나머지)\n", a % b);
    printf("a / (double)b = %.3f\n", a / (double)b);

    return 0;
}
▶ 실행 결과
a = 17, b = 5
a + b = 22
a - b = 12
a * b = 85
a / b = 3  (정수 나눗셈)
a % b = 2  (나머지)
a / (double)b = 3.400
ex02_increment.c전위와 후위 차이
CODE
#include <stdio.h>

int main(void) {
    int a = 5;
    int b;

    b = a++;       // 후위: a 사용 후 증가
    printf("후위: a=%d, b=%d\n", a, b);   // a=6, b=5

    a = 5;
    b = ++a;       // 전위: a 먼저 증가
    printf("전위: a=%d, b=%d\n", a, b);   // a=6, b=6

    a += 10;       // a = a + 10
    printf("a += 10 -> %d\n", a);

    a *= 2;
    printf("a *= 2  -> %d\n", a);

    return 0;
}
▶ 실행 결과
후위: a=6, b=5
전위: a=6, b=6
a += 10 -> 16
a *= 2  -> 32
ex03_logical.c관계와 논리
CODE
#include <stdio.h>

int main(void) {
    int a = 10, b = 20;

    printf("a == b : %d\n", a == b);
    printf("a != b : %d\n", a != b);
    printf("a <  b : %d\n", a <  b);
    printf("a >= b : %d\n", a >= b);

    int age = 25;
    int has_license = 1;

    printf("성인이고 면허 있음: %d\n", (age >= 18) && has_license);
    printf("미성년 또는 면허 없음: %d\n", (age < 18) || !has_license);

    return 0;
}
▶ 실행 결과
a == b : 0
a != b : 1
a <  b : 1
a >= b : 0
성인이고 면허 있음: 1
미성년 또는 면허 없음: 0
ex04_cast.c캐스팅의 위력
CODE
#include <stdio.h>

int main(void) {
    int total = 95, count = 4;

    double avg_wrong = total / count;
    double avg_right = (double)total / count;

    printf("잘못된 평균(정수 나눗셈): %.3f\n", avg_wrong);  // 23.000
    printf("올바른 평균(캐스팅):       %.3f\n", avg_right); // 23.750

    double pi = 3.99;
    int trunc = (int)pi;
    printf("(int)3.99 = %d  (소수점 절단)\n", trunc);

    return 0;
}
▶ 실행 결과
잘못된 평균(정수 나눗셈): 23.000
올바른 평균(캐스팅):       23.750
(int)3.99 = 3  (소수점 절단)

📝 과제 (exercises)

직접 풀어보고, 막힐 때 정답을 펼쳐 비교해보세요.

과제 1

문제 1 (hw01.c)

목표: 두 정수 `a`, `b`를 입력받아 다음을 모두 출력하세요. - 합/차/곱/몫/나머지 - a를 b로 나눈 실수 결과 (소수점 둘째 자리)

요구사항
  • 파일명: hw01.c
정답 코드 펼치기 / 접기
SOLUTION
#include <stdio.h>

int main(void) {
    int a, b;
    printf("두 정수 입력: ");
    scanf("%d %d", &a, &b);

    printf("합:    %d\n", a + b);
    printf("차:    %d\n", a - b);
    printf("곱:    %d\n", a * b);
    if (b != 0) {
        printf("몫:    %d\n", a / b);
        printf("나머지: %d\n", a % b);
        printf("실수 나눗셈: %.2f\n", (double)a / b);
    } else {
        printf("0으로 나눌 수 없습니다.\n");
    }
    return 0;
}
과제 2

문제 2 (hw02.c)

목표: 정수 하나를 입력받아 **짝수/홀수 여부**와 **양수/음수/0** 여부를 함께 출력하세요. 조건문이 아닌 **연산자 결과**(0/1)만 사용해 보세요.

요구사항
  • 파일명: hw02.c
입출력 예시
입력: -4
짝수=1, 양수=0, 음수=1
정답 코드 펼치기 / 접기
SOLUTION
#include <stdio.h>

int main(void) {
    int n;
    printf("정수 입력: ");
    scanf("%d", &n);

    int even     = (n % 2 == 0);
    int positive = (n > 0);
    int negative = (n < 0);

    printf("짝수=%d, 양수=%d, 음수=%d\n", even, positive, negative);
    return 0;
}
▶ 실행 결과
입력: -4
짝수=1, 양수=0, 음수=1
과제 3

문제 3 (hw03.c)

목표: 화씨 온도(`F`)를 입력받아 섭씨로 변환해 출력하세요. 공식: `C = (F - 32) * 5 / 9`. **정수 나눗셈에 주의**.

요구사항
  • 파일명: hw03.c
정답 코드 펼치기 / 접기
SOLUTION
#include <stdio.h>

int main(void) {
    double f;
    printf("화씨 온도 입력: ");
    scanf("%lf", &f);

    double c = (f - 32) * 5.0 / 9.0;
    printf("섭씨: %.2f\n", c);
    return 0;
}
예제 코드 / 강의 자료

전체 강의 자료와 예제 코드는 GitHub에서 자유롭게 받아볼 수 있습니다.

GitHub에서 보기 ↗