본문으로 건너뛰기
Previous
Next
C++ if / else / switch: Conditionals, Pitfalls, and switch

C++ if / else / switch: Conditionals, Pitfalls, and switch

C++ if / else / switch: Conditionals, Pitfalls, and switch

이 글의 핵심

Complete guide to C++ conditionals: if/else chains, switch with fall-through, the = vs == bug, floating-point comparison, and C++17 if-with-initializer. Covers every form with working examples.

if / else Basics

#include <iostream>

int main() {
    int age = 20;

    if (age >= 18) {
        std::cout << "adult\n";
    } else {
        std::cout << "minor\n";
    }
}

The condition must evaluate to bool (or be convertible to it). In C++, any non-zero integer, non-null pointer, or non-empty container converts to true.

else if Chains

Use else if to test multiple conditions in sequence. Only the first matching branch runs:

int score = 85;

if (score >= 90) {
    std::cout << "A\n";
} else if (score >= 80) {
    std::cout << "B\n";
} else if (score >= 70) {
    std::cout << "C\n";
} else if (score >= 60) {
    std::cout << "D\n";
} else {
    std::cout << "F\n";
}
// Output: B

Comparison and Logical Operators

// Comparison operators
a == b  // equal
a != b  // not equal
a <  b  // less than
a >  b  // greater than
a <= b  // less than or equal
a >= b  // greater than or equal

// Logical operators
a && b  // AND — true if both are true
a || b  // OR — true if at least one is true
!a      // NOT — inverts the truth value

Combining:

int x = 15;

if (x > 10 && x < 20) {
    std::cout << "in range\n";  // true: x is between 10 and 20
}

if (x < 0 || x > 100) {
    std::cout << "out of bounds\n";  // false: x is 15
}

bool valid = !(x < 0);  // true — x is not negative

Short-circuit evaluation: && stops at the first false, || stops at the first true. This matters when the right side has side effects or can crash:

// Safe: if ptr is null, ptr->value is never evaluated
if (ptr != nullptr && ptr->value > 0) {
    // ...
}

switch Statement

switch dispatches on the value of an integral expression. Each case tests for a specific value:

#include <iostream>
#include <string>

int main() {
    int day = 3;
    std::string name;

    switch (day) {
        case 1: name = "Monday";    break;
        case 2: name = "Tuesday";   break;
        case 3: name = "Wednesday"; break;
        case 4: name = "Thursday";  break;
        case 5: name = "Friday";    break;
        case 6: name = "Saturday";  break;
        case 7: name = "Sunday";    break;
        default: name = "Invalid";  break;
    }

    std::cout << name << '\n';  // Wednesday
}

switch works with int, char, enum, and other integral types. It does not work with std::string or floating-point types.

Fall-Through

Without break, execution falls through to the next case. This is usually a bug but sometimes intentional:

int month = 4;
int days;

switch (month) {
    case 1: case 3: case 5: case 7:
    case 8: case 10: case 12:
        days = 31; break;  // all months with 31 days
    case 4: case 6: case 9: case 11:
        days = 30; break;  // months with 30 days
    case 2:
        days = 28; break;  // February (ignoring leap years)
    default:
        days = -1; break;
}

When fall-through is intentional, mark it explicitly with [[fallthrough]] (C++17) to suppress compiler warnings and communicate intent:

switch (status) {
    case Status::Pending:
        prepare();
        [[fallthrough]];  // intentionally falls through to Active
    case Status::Active:
        process();
        break;
    case Status::Done:
        cleanup();
        break;
}

switch vs if-else

Use switch whenUse if-else when
Testing one value against discrete constantsTesting ranges (x > 10 && x < 20)
Many cases for the same expressionConditions involve different variables
enum dispatchFloating-point comparisons
Performance-critical dispatch (jump table)String matching

C++17: if with Initializer

C++17 lets you initialize a variable in the if condition, scoped to the if/else:

// Variable scoped to the if block
if (auto it = map.find("key"); it != map.end()) {
    std::cout << "Found: " << it->second << '\n';
}
// 'it' is not accessible here

// Useful with try-like patterns
if (int result = compute(); result > 0) {
    std::cout << "Positive: " << result << '\n';
} else if (result < 0) {
    std::cout << "Negative: " << result << '\n';
} else {
    std::cout << "Zero\n";
}

Ternary Operator

A compact inline conditional for simple value selection:

int a = 5, b = 3;
int max = (a > b) ? a : b;  // max is 5

std::string status = (score >= 60) ? "pass" : "fail";

Avoid nesting ternaries — it quickly becomes unreadable:

// Too hard to read — use if-else instead
int grade = (s >= 90) ? 4 : (s >= 80) ? 3 : (s >= 70) ? 2 : (s >= 60) ? 1 : 0;

// Clearer:
int grade;
if (s >= 90) grade = 4;
else if (s >= 80) grade = 3;
else if (s >= 70) grade = 2;
else if (s >= 60) grade = 1;
else grade = 0;

Common Mistakes

Mistake 1: Assignment Instead of Comparison (= vs ==)

int x = 10;

if (x = 5) {  // BUG — assigns 5 to x, condition is true (5 != 0)
    std::cout << "always runs\n";
}

if (x == 5) {  // CORRECT — compares x to 5
    std::cout << "runs when x is 5\n";
}

Compile with -Wall to get a warning about this. Some codebases use “Yoda conditions” (5 == x) as a style choice to prevent this, since 5 = x is a compile error.

Mistake 2: Missing break in switch

int n = 2;
switch (n) {
    case 1:
        std::cout << "one\n";
    case 2:
        std::cout << "two\n";  // this runs
    case 3:
        std::cout << "three\n";  // this ALSO runs — missing break!
    default:
        std::cout << "other\n";  // and this — missing break!
}
// Output: two / three / other  (not what was intended)

Mistake 3: Stray Semicolon After if

if (age >= 18);  // semicolon — empty statement, if does nothing
{
    std::cout << "always runs\n";  // runs unconditionally
}

// Correct:
if (age >= 18) {
    std::cout << "adult\n";
}

Mistake 4: Comparing Floating-Point with ==

double x = 0.1 + 0.2;
if (x == 0.3) {  // FALSE — floating-point rounding means x is 0.30000000000000004
    std::cout << "equal\n";
}

// Correct: use a tolerance
const double epsilon = 1e-9;
if (std::fabs(x - 0.3) < epsilon) {
    std::cout << "equal\n";  // true
}

Mistake 5: Variable Scope in switch

Declaring a variable inside a case without braces can cause “jump over initialization” errors:

switch (n) {
    case 1:
        int x = 10;  // error — x would be in scope for case 2 but not initialized
        break;
    case 2:
        std::cout << x << '\n';  // which x?
        break;
}

// Fix: add braces
switch (n) {
    case 1: {
        int x = 10;
        std::cout << x << '\n';
        break;
    }
    case 2: {
        std::cout << "two\n";
        break;
    }
}

Practical Example: Menu System

#include <iostream>
#include <string>

int main() {
    int choice;

    while (true) {
        std::cout << "\n1. Deposit\n2. Withdraw\n3. Balance\n4. Quit\n";
        std::cout << "Choice: ";
        std::cin >> choice;

        switch (choice) {
            case 1: {
                double amount;
                std::cout << "Amount: ";
                std::cin >> amount;
                if (amount <= 0) {
                    std::cout << "Invalid amount\n";
                } else {
                    std::cout << "Deposited $" << amount << '\n';
                }
                break;
            }
            case 2: {
                double amount;
                std::cout << "Amount: ";
                std::cin >> amount;
                if (amount <= 0) {
                    std::cout << "Invalid amount\n";
                } else {
                    std::cout << "Withdrew $" << amount << '\n';
                }
                break;
            }
            case 3:
                std::cout << "Balance: $1000.00\n";
                break;
            case 4:
                std::cout << "Goodbye!\n";
                return 0;
            default:
                std::cout << "Invalid choice\n";
                break;
        }
    }
}

Key Takeaways

  • if / else if / else for range tests and complex conditions; switch for exact discrete values
  • Always add break after each case — use [[fallthrough]] (C++17) to document intentional fall-through
  • = vs ==: the most common beginner bug — enable -Wall to catch it
  • switch works with integral types and enum — not std::string or double
  • Floating-point equality with == is almost always wrong — use a tolerance with fabs(a - b) < epsilon
  • C++17 if (init; cond) scopes variables to the if-block, reducing namespace pollution
  • Braces inside switch cases allow local variable declarations without scoping issues

자주 묻는 질문 (FAQ)

Q. 이 내용을 실무에서 언제 쓰나요?

A. Complete guide to C++ conditionals: comparison and logical operators, switch vs if-else, fall-through, [[fallthrough]], … 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.

Q. 선행으로 읽으면 좋은 글은?

A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. C++ 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.

Q. 더 깊이 공부하려면?

A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.


같이 보면 좋은 글 (내부 링크)

이 주제와 연결되는 다른 글입니다.


이 글에서 다루는 키워드 (관련 검색어)

C++, if, switch, else, control flow 등으로 검색하시면 이 글이 도움이 됩니다.