본문으로 건너뛰기 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

Frequently Asked Questions (FAQ)

Q. When would I use this in practice?

A. Complete guide to C++ conditionals: comparison and logical operators, switch vs if-else, fall-through, [[fallthrough]], …

Q. What should I read before this?

A. Follow the previous article or related articles links at the bottom of each post to learn in sequence. See the C++ series index for the full picture.

Q. Where can I study this more deeply?

A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.


Other articles related to this topic.


Keywords Covered in This Article (Related Search Terms)

This article covers C++, if, switch, else, control flow.