---
title: "갈림길을 정하는 것은 bool 하나다"
description: "괄호 안이 아무리 길어도 결과는 true 아니면 false 하나입니다. 그 한 값이 실행이 지나갈 길을 고릅니다."
author: "유니얼"
pubDate: 2026-09-08
category: "programming/csharp/basics"
tags: ["C#", "기초"]
canonical: https://blog.unialgames.com/posts/csharp-if-else/
---
여기까지 쓴 코드는 전부 위에서 아래로 한 줄씩 실행됐습니다.

```csharp
Console.WriteLine("첫 번째");
Console.WriteLine("두 번째");
Console.WriteLine("세 번째");
```

적힌 순서 그대로 세 줄이 나옵니다. 아무 문법도 쓰지 않으면 프로그램은 직선 한 줄입니다.

> **흐름을 바꾸는 방법은 두 가지뿐입니다. 갈라지거나, 되돌아가거나.**

## 흐름을 바꾸는 방법은 두 가지뿐이다

<figure class="diagram">
<svg viewBox="0 0 680 240" role="img" aria-label="갈라지기는 조건에서 두 갈래로 나뉘었다가 다시 합쳐지고, 되돌아가기는 본문을 지나 조건으로 되돌아오는 그림">
<text x="20" y="26" fill="var(--text-muted)" font-size="13">갈라지기</text>
<text x="380" y="26" fill="var(--text-muted)" font-size="13">되돌아가기</text>
<g fill="var(--bg)" stroke="var(--border)">
<rect x="110" y="44" width="110" height="40" rx="6"></rect>
<rect x="26" y="132" width="110" height="40" rx="6"></rect>
<rect x="194" y="132" width="110" height="40" rx="6"></rect>
<rect x="110" y="196" width="110" height="36" rx="6"></rect>
<rect x="430" y="44" width="110" height="40" rx="6"></rect>
<rect x="430" y="132" width="110" height="40" rx="6"></rect>
<rect x="430" y="196" width="110" height="36" rx="6"></rect>
</g>
<g stroke="var(--text-muted)" stroke-width="1.4" fill="none">
<path d="M150 84 L81 128"></path>
<path d="M180 84 L249 128"></path>
<path d="M81 172 L150 192"></path>
<path d="M249 172 L180 192"></path>
<path d="M485 84 L485 128"></path>
<path d="M540 152 L588 152 L588 64 L544 64"></path>
<path d="M485 172 L485 192"></path>
</g>
<g fill="var(--text-muted)" stroke="none">
<path d="M81 128 l-5 -9 l10 0 z"></path>
<path d="M249 128 l-5 -9 l10 0 z"></path>
<path d="M485 128 l-5 -9 l10 0 z"></path>
<path d="M485 192 l-5 -9 l10 0 z"></path>
<path d="M544 64 l9 -5 l0 10 z"></path>
</g>
<g text-anchor="middle" font-size="13">
<text x="165" y="69" fill="var(--accent)">조건</text>
<text x="81" y="157" fill="var(--text)">참일 때</text>
<text x="249" y="157" fill="var(--text)">거짓일 때</text>
<text x="165" y="219" fill="var(--text-muted)">이어서 계속</text>
<text x="485" y="69" fill="var(--accent)">조건</text>
<text x="485" y="157" fill="var(--text)">본문</text>
<text x="485" y="219" fill="var(--text-muted)">이어서 계속</text>
</g>
<g text-anchor="middle" font-size="11" fill="var(--text-muted)">
<text x="88" y="106">참</text>
<text x="244" y="106">거짓</text>
<text x="612" y="108">거짓이 될</text>
<text x="612" y="122">때까지</text>
</g>
</svg>
<figcaption>왼쪽은 한쪽만 지나간다. 오른쪽은 같은 자리로 돌아온다.</figcaption>
</figure>

왼쪽이 조건문(`if`, `switch`), 오른쪽이 반복문(`while`, `for`)입니다.
이 글은 왼쪽만 다룹니다.

## if 는 이렇게 생겼다

갈라지기를 맡는 문법이 `if` 입니다. 생김새는 세 부분입니다.

<figure class="diagram">
<svg viewBox="0 0 680 200" role="img" aria-label="if 키워드, 괄호 안의 조건, 중괄호 안의 블록으로 나뉜 if 문의 생김새">
<g font-family="var(--font-mono)" font-size="18">
<text x="40" y="52" fill="var(--accent)">if</text>
<text x="76" y="52" fill="var(--text-muted)">(</text>
<text x="92" y="52" fill="var(--text)">조건</text>
<text x="140" y="52" fill="var(--text-muted)">)</text>
<text x="40" y="88" fill="var(--text-muted)">{</text>
<text x="72" y="124" fill="var(--text)">참일 때 실행할 코드</text>
<text x="40" y="160" fill="var(--text-muted)">}</text>
</g>
<g stroke="var(--border)" stroke-width="1.4" fill="none">
<path d="M52 34 L52 22 L300 22"></path>
<path d="M116 60 L116 78 L300 78"></path>
<path d="M285 124 L300 124"></path>
</g>
<g font-size="13" fill="var(--text-muted)">
<text x="312" y="27">이 자리에서 갈라진다는 표시</text>
<text x="312" y="83">참인지 거짓인지 묻는 자리. 괄호는 생략할 수 없다</text>
<text x="312" y="129">참일 때만 실행되는 블록</text>
</g>
</svg>
<figcaption>키워드, 괄호 안의 조건, 중괄호 안의 블록.</figcaption>
</figure>

실제로 값을 넣어 보면 이렇습니다.

```csharp
int hp = 30;

if (hp <= 50)
{
    Console.WriteLine("체력이 낮습니다");
}
```

`hp` 가 30이니 조건이 참이고, 블록 안이 실행됩니다.
`hp` 가 80이었다면 블록은 건너뛰고 아래로 지나갑니다.

거짓일 때 할 일이 따로 있으면 `else` 를 붙입니다.

```csharp
if (hp <= 50)
{
    Console.WriteLine("체력이 낮습니다");
}
else
{
    Console.WriteLine("아직 괜찮습니다");
}
```

`else` 에는 괄호가 없습니다. 물어볼 것이 없기 때문입니다.
위의 `if` 가 거짓이었다는 사실이 이미 조건입니다.

여기서 자주 나오는 실수가 하나 있습니다. 괄호 뒤에 세미콜론을 찍는 것입니다.

```csharp
if (hp <= 50);      // 여기 세미콜론
{
    Console.WriteLine("체력이 낮습니다");
}
```

세미콜론 하나로 `if` 는 그 자리에서 끝나 버립니다.
아래 중괄호는 `if` 와 아무 상관 없는 블록이 되어 **항상** 실행됩니다.
컴파일은 됩니다. 경고 한 줄만 나오고 넘어갑니다.

## 괄호 안은 결국 값 하나로 줄어든다

그럼 괄호 안에는 무엇을 넣을 수 있을까요.

앞 글에서 식은 값 하나만 남을 때까지 줄어든다고 했습니다.
`if` 의 괄호 안도 똑같은 식입니다. 다만 남는 값의 타입이 정해져 있습니다.

<x-eval>
<script type="application/json">
{
  "label": "조건도 식이다",
  "cases": [
    {
      "label": "age = 25, isStudent = false",
      "steps": [
        { "text": "[age >= 19] && !isStudent", "why": "비교 연산자가 먼저 값이 됩니다. 25 는 19 이상이니 참입니다." },
        { "text": "true && [!isStudent]", "why": "isStudent 가 거짓이니 ! 를 붙이면 참이 됩니다." },
        { "text": "[true && true]", "why": "&& 는 둘 다 참일 때만 참입니다." },
        { "text": "true", "why": "값 하나만 남았습니다. 이 한 값이 길을 고릅니다." }
      ],
      "note": "괄호 안이 길든 짧든 마지막에 남는 것은 언제나 값 하나입니다."
    }
  ]
}
</script>
</x-eval>

그 값의 타입이 `bool` 입니다. `true` 아니면 `false`, 둘뿐입니다.

C# 은 조건 자리에 `bool` 말고 다른 것을 허용하지 않습니다.

```csharp
int n = 1;

if (n)        // 컴파일 에러: int 를 bool 로 바꿀 수 없습니다
{
}
```

C 계열의 오래된 언어들은 `0` 을 거짓, 나머지를 참으로 봤습니다.
그래서 `if (n == 1)` 을 쓰려다 `=` 를 하나 빠뜨려 `if (n = 1)` 이라고 적어도
그대로 컴파일됐습니다. 대입한 값 `1` 이 참으로 읽혀서 조건은 늘 참이 되고,
`n` 은 조용히 바뀝니다.

C# 은 조건 자리를 `bool` 로 막아서 이 실수를 컴파일 단계에서 잡습니다.

## 둘 중 하나만 실행된다

이제 실제로 갈라지는 코드입니다.

<x-flow>
<script type="application/json">
{
  "label": "실행이 지나가는 자리",
  "lines": [
    "if (number > 0)",
    "{",
    "    Console.WriteLine(\"양수입니다\");",
    "}",
    "else",
    "{",
    "    Console.WriteLine(\"양수가 아닙니다\");",
    "}",
    "Console.WriteLine(\"여기는 항상 지나갑니다\");"
  ],
  "cases": [
    {
      "label": "number = 10",
      "state": "number = 10",
      "path": [
        { "line": 0, "why": "괄호 안이 값 하나로 줄어듭니다.", "verdict": "true" },
        { "line": 2, "why": "참이므로 if 블록으로 들어옵니다.", "out": "양수입니다" },
        { "line": 8, "why": "블록을 빠져나와 다시 한 줄로 이어집니다.", "out": "여기는 항상 지나갑니다" }
      ],
      "skip": [4, 5, 6, 7],
      "note": "흐린 줄은 이번 실행에서 한 번도 읽히지 않은 코드입니다."
    },
    {
      "label": "number = -3",
      "state": "number = -3",
      "path": [
        { "line": 0, "why": "같은 코드인데 값이 달라졌습니다.", "verdict": "false" },
        { "line": 6, "why": "거짓이므로 else 블록으로 갑니다.", "out": "양수가 아닙니다" },
        { "line": 8, "why": "어느 쪽으로 갔든 여기서 다시 만납니다.", "out": "여기는 항상 지나갑니다" }
      ],
      "skip": [1, 2, 3],
      "note": "코드는 한 글자도 안 바뀌었습니다. 바뀐 것은 bool 값 하나입니다."
    }
  ]
}
</script>
</x-flow>

두 가지가 보입니다.

**한쪽은 아예 실행되지 않습니다.** 건너뛴 줄은 느려지는 것이 아니라 지나가지도 않습니다.
둘 다 조금씩 실행되는 일은 없습니다.

**갈라진 길은 아래에서 다시 합쳐집니다.** `if` 는 흐름을 영원히 나누는 것이 아니라
잠깐 갈랐다가 되돌려 놓습니다. 블록이 끝나면 다시 한 줄입니다.

## else 를 안 쓰면 거짓일 때 아무 일도 없다

`else` 는 필수가 아닙니다.

```csharp
if (score >= 60)
{
    Console.WriteLine("합격");
}

Console.WriteLine("확인 끝");
```

`score` 가 40이면 출력은 `확인 끝` 한 줄뿐입니다.
불합격이라고 알려주는 코드가 어디에도 없으니까요.

`else` 는 조건의 반대편이 아니라 **남은 전부**입니다.
위에서 걸리지 않은 모든 경우가 여기로 옵니다.

## 중괄호는 생략할 수 있지만 쓰는 편이 낫다

블록이 한 줄이면 중괄호를 뺄 수 있습니다.

```csharp
if (isReady)
    Start();
```

문제는 나중입니다. 한 줄을 더 붙이는 순간 이렇게 됩니다.

```csharp
if (isReady)
    Start();
    Log("시작함");     // if 와 상관없이 항상 실행됩니다
```

들여쓰기는 사람이 보라고 있는 것이고, 컴파일러는 들여쓰기를 보지 않습니다.
중괄호가 없으면 `if` 에 딸린 것은 **바로 다음 문장 하나**뿐입니다.

처음부터 중괄호를 쓰면 이 실수가 생길 자리가 없습니다.

## 조건이 길어지면 이름을 붙인다

조건은 그냥 `bool` 값입니다. 변수에 담을 수 있다는 뜻입니다.

```csharp
if (age >= 19 && !isStudent && hasTicket && !isBanned)
{
    Enter();
}
```

```csharp
bool canEnter = age >= 19 && !isStudent && hasTicket && !isBanned;

if (canEnter)
{
    Enter();
}
```

두 코드는 하는 일이 같습니다. 아래쪽은 읽는 사람이 `if` 한 줄만 보고
"들어갈 수 있으면 들어간다"를 알 수 있습니다.
조건이 왜 그런지가 궁금할 때만 위를 봅니다.

## 정리

- 아무 문법도 안 쓰면 코드는 위에서 아래로 한 줄씩입니다.
- `if (조건) { ... }` 가 기본형입니다. 괄호는 못 빼고, 괄호 뒤에 세미콜론을 찍으면 거기서 끝납니다.
- 흐름을 바꾸는 방법은 갈라지기와 되돌아가기, 두 가지뿐입니다.
- `if` 의 괄호 안도 식입니다. 줄어들어서 `bool` 값 하나가 남습니다.
- C# 은 조건 자리에 `bool` 만 받습니다. `if (n)` 은 컴파일 에러입니다.
- 갈라진 두 길 중 한쪽만 실행되고, 블록이 끝나면 다시 한 줄로 합쳐집니다.
- `else` 를 안 쓰면 거짓일 때 아무 일도 일어나지 않습니다.
- 중괄호를 빼면 `if` 에 딸리는 것은 다음 문장 하나뿐입니다.