본문으로 건너뛰기

안동민 개발노트

본문 시작

관계 연산자와 논리 연산자

비교식이 만드는 bool 값과 논리 연산의 단락 평가를 이해하고 여러 조건을 정확한 판단식으로 조합합니다.

프로그램은 단순히 계산만 하는 것이 아니라 특정 조건에 따라 다른 동작을 수행해야 할 때가 많습니다.

예를 들어 만약 점수가 60점 이상이면 합격과 같은 조건을 판단해야 합니다.

이때 필요한 것이 바로 관계 연산자(Relational Operators)논리 연산자(Logical Operators)입니다.

이 장에서는 두 값의 크기를 비교하고, 여러 조건을 조합해 참(true)/거짓(false)을 판단하는 방법을 살펴봅니다.

이 연산자들은 앞으로 배우게 될 조건문(if), 반복문(for, while)의 핵심적인 구성 요소가 됩니다.

비교는 bool을 만들고, 논리는 실행 조건을 고른다

관계 연산자는 두 값을 비교해 true 또는 false 를 만들고, 논리 연산자는 그 결과들을 하나의 조건으로 묶습니다.

  1. 값 비교

    score >= 60 true 크기나 동등성 관계를 비교해 bool 값을 만듭니다.

  2. bool 보관

    bool passed = ... passed 비교 결과는 변수에 담거나 바로 조건식에 사용할 수 있습니다.

  3. 조건 조합

    passed && attended AND && , || , ! 로 판단을 묶거나 뒤집습니다.

  4. 분기 결정

    if (canPass) branch 최종 bool이 참이면 조건문이나 반복문 본문이 실행됩니다.

  5. 60점 이상이면 합격

    입력 int score = 75; 관계 연산 score >= 60 논리 조합 (score >= 60) && submitted


관계 연산자 (Relational Operators)

관계 연산자와 논리 연산자는 값의 형태, 평가 순서, 경계 입력에서 먼저 확인합니다.

관계 연산자는 비교 질문에 bool로 답한다

왼쪽 값과 오른쪽 값을 비교한 결과는 숫자가 아니라 true 또는 false 입니다.

  1. 동등성 비교

    같은지 묻기 == != 값이 같은지, 또는 다른지를 bool로 판단합니다.

  2. 크기 비교

    큰지 묻기 > < 한쪽 값이 다른 쪽보다 큰지 또는 작은지를 비교합니다.

  3. 범위 비교

    경계 포함 >= <= 합격 점수처럼 기준값을 포함해야 할 때 사용합니다.

관계 연산자는 두 피연산자 간의 크기 또는 동등성 관계를 비교하여 그 결과로 true (참) 또는 false (거짓)의 bool 타입 값을 반환합니다.

연산자이름설명예시 (결과)
==같다 (Equal to)두 피연산자의 값이 같으면 true, 아니면 false.5 == 5 (true)
!=같지 않다 (Not equal to)두 피연산자의 값이 다르면 true, 아니면 false.5 != 3 (true)
>보다 크다 (Greater than)왼쪽 피연산자가 오른쪽보다 크면 true.5 > 3 (true)
<보다 작다 (Less than)왼쪽 피연산자가 오른쪽보다 작으면 true.5 < 3 (false)
>=보다 크거나 같다 (Greater than or equal to)왼쪽 피연산자가 오른쪽보다 크거나 같으면 true.5 >= 5 (true)
<=보다 작거나 같다 (Less than or equal to)왼쪽 피연산자가 오른쪽보다 작거나 같으면 true.5 <= 3 (false)
주의사항
  • 같다(==)와 대입(=)의 혼동 금지: ==는 비교 연산자이고 =는 대입 연산자입니다. 초보자가 가장 자주 하는 실수 중 하나이므로 항상 주의해야 합니다. if (a = 10)처럼 실수로 대입 연산자를 사용하면 컴파일러 경고가 발생하거나(C++17부터는 특정 상황에서 오류 처리 가능), 의도치 않게 a에 10이 할당되고 조건문이 항상 참이 되는 심각한 버그를 만들 수 있습니다.
  • 실수 비교의 주의: 부동 소수점 수(float, double)는 컴퓨터 내부 표현 방식 때문에 미세한 오차가 발생할 수 있습니다. 따라서 두 실수가 정확히 같은지 ==로 비교하는 것은 위험합니다. 대신, 두 실수의 차이가 아주 작은 값(epsilon)보다 작으면 같다고 간주하는 방식을 사용합니다.
    double a = 0.1 + 0.2; // a는 정확히 0.3이 아닐 수 있음 (예: 0.30000000000000004)
    double b = 0.3;
    if (a == b) { // 대부분 false로 나옴
        std::cout << "a와 b는 같다 (직접 비교)" << std::endl;
    } else {
        std::cout << "a와 b는 다르다 (직접 비교)" << std::endl; // 이 메시지가 출력될 확률이 높음
    }
    const double EPSILON = 0.00000001; // 아주 작은 값 정의
    if (std::abs(a - b) < EPSILON) { // std::abs는 <cmath>에 있음
        std::cout << "a와 b는 거의 같다 (엡실론 비교)" << std::endl; // 이 메시지가 출력
    }
예시
#include <iostream> // std::cout, std::endl 사용
#include <string>   // std::string 사용
#include <cmath>    // std::abs 사용 (실수 비교를 위해)

int main() {
    int score = 75;
    int passingScore = 60;
    std::string name1 = "Alice";
    std::string name2 = "Bob";
    std::string name3 = "Alice";

    // 점수 비교
    bool isPassed = (score >= passingScore);
    std::cout << "합격 여부 (score >= passingScore): " << std::boolalpha << isPassed << std::endl; // true

    bool isPerfect = (score == 100);
    std::cout << "만점 여부 (score == 100): " << std::boolalpha << isPerfect << std::endl;   // false

    // 문자열 비교 (문자열 비교는 기본적으로 사전 순 비교)
    bool namesEqual = (name1 == name2);
    std::cout << "이름 같음 (name1 == name2): " << std::boolalpha << namesEqual << std::endl; // false

    bool namesNotEqual = (name1 != name3);
    std::cout << "이름 같지 않음 (name1 != name3): " << std::boolalpha << namesNotEqual << std::endl; // false

    bool nameOrder = (name1 < name2); // 'A'가 'B'보다 앞서므로 true
    std::cout << "사전순 비교 (name1 < name2): " << std::boolalpha << nameOrder << std::endl; // true

    return 0;
}

논리 연산자 (Logical Operators)

논리 연산자는 bool 타입 피연산자를 사용하여 논리적인 연산(AND, OR, NOT)을 수행하고 그 결과로 true 또는 falsebool 타입 값을 반환합니다.

관계 연산자의 결과(true/false)나 다른 bool 변수를 조합하여 더 복잡한 조건을 만들 때 사용됩니다.

연산자이름설명예시 (결과)
&&논리 AND (Logical AND)두 피연산자 모두 true일 때만 true, 아니면 false.(true && false) (false)
||논리 OR (Logical OR)두 피연산자 중 하나라도 true이면 true, 모두 false일 때만 false.(true || false) (true)
!논리 NOT (Logical NOT)피연산자의 논리 값을 반전시킵니다. (truefalse로, falsetrue로).!true (false)

논리 AND(&&): 두 조건이 모두 참일 때만 전체 결과가 참이 됩니다.

A && B

  • A가 true이고 B가 true일 때 -> true
  • A가 true이고 B가 false일 때 -> false
  • A가 false이고 B가 true일 때 -> false
  • A가 false이고 B가 false일 때 -> false

논리 OR(||): 두 조건 중 하나라도 참일 때 전체 결과가 참이 됩니다. A || B

  • A가 true이고 B가 true일 때 -> true
  • A가 true이고 B가 false일 때 -> true
  • A가 false이고 B가 true일 때 -> true
  • A가 false이고 B가 false일 때 -> false

논리 NOT(!): 단항 연산자로, 피연산자의 논리 값을 반전시킵니다.

!A

  • A가 true일 때 -> false
  • A가 false일 때 -> true

단락 평가 (Short-Circuit Evaluation): &&|| 연산자는 단락 평가라는 특징을 가집니다.

이는 연산의 결과를 결정하기 위해 모든 피연산자를 평가할 필요가 없을 때, 더 이상 평가를 진행하지 않는다는 의미입니다.

  • A && B: 만약 Afalse라면, B의 값에 관계없이 전체 표현식은 false가 됩니다. 따라서 B는 평가되지 않습니다.
  • A || B: 만약 Atrue라면, B의 값에 관계없이 전체 표현식은 true가 됩니다. 따라서 B는 평가되지 않습니다.

이러한 단락 평가는 특정 조건이 만족될 때만 안전하게 다음 코드를 실행해야 하는 경우에 유용합니다.

예를 들어 포인터가 유효한지 먼저 확인한 후, 그 포인터를 사용하는 코드를 실행할 때 활용됩니다.

아래 다이어그램은 비교식이 bool 값이 되고, 논리 연산자로 조합된 뒤 단락 평가를 거쳐 조건문에서 사용되는 흐름을 보여줍니다.

왼쪽 조건만으로 결과가 정해지면 오른쪽은 실행하지 않는다

&& 와 || 는 결과가 이미 확정되는 순간 남은 표현식 평가를 멈춥니다.

  1. 모두 참이어야 참
    A && B

    모두 참이어야 참 A == false B를 보지 않아도 전체 결과는 false입니다. B 생략 A == true 전체 결과를 알기 위해 B까지 평가합니다. B 평가

  2. 하나만 참이어도 참
    A || B

    하나만 참이어도 참 A == true B를 보지 않아도 전체 결과는 true입니다. B 생략 A == false 참인 조건이 있는지 B까지 평가합니다. B 평가

  3. 안전한 접근 순서

    ptr != nullptr && ptr->member == value 왼쪽에서 포인터가 유효한지 먼저 확인하면, null인 경우 오른쪽 멤버 접근이 실행되지 않습니다.

  4. 보호 조건

    왼쪽에 둡니다.

  5. 왼쪽 결과

    false이면 위험한 오른쪽 접근은 생략됩니다.

  6. 부작용

    있는 함수 호출도 생략될 수 있음을 기억합니다.

단락 평가 예시
// if (ptr != nullptr && ptr->member == value) { ... }
// 만약 ptr이 nullptr이면, ptr != nullptr이 false가 되어 ptr->member에 접근하지 않아 안전함.
논리 연산자 예시
#include <iostream>

int main() {
    int age = 20;
    bool hasLicense = true;
    bool hasCar = false;
    int points = 85;

    // 성인이고 면허가 있는지 (AND)
    bool canDrive = (age >= 18) && hasLicense;
    std::cout << "운전 가능 (성인 && 면허): " << std::boolalpha << canDrive << std::endl; // true

    // 면허가 있거나 차가 있는지 (OR)
    bool needsTransport = hasLicense || hasCar;
    std::cout << "교통수단 필요 (면허 || 차): " << std::boolalpha << needsTransport << std::endl; // true (면허가 있으므로)

    // 시험에 불합격했는지 (NOT)
    bool isFailed = !(points >= 70); // 70점 이상이면 합격이므로, 그 반대는 불합격
    std::cout << "시험 불합격 (만점 여부): " << std::boolalpha << isFailed << std::endl; // false (85점은 합격)

    // 복합 조건
    bool canRentCar = (age >= 21) && hasLicense && (points >= 80);
    std::cout << "렌터카 가능 (복합 조건): " << std::boolalpha << canRentCar << std::endl; // false (age >= 21이 false)

    return 0;
}

C++ 연산자 우선순위와 결합 규칙

복잡한 표현식에서는 산술 연산자, 관계 연산자, 논리 연산자가 함께 사용될 수 있습니다.

이때 어떤 연산이 먼저 수행될지 이해하는 것이 중요합니다.

일반적인 우선순위는 다음과 같습니다 (높은 것에서 낮은 것 순)

단항 연산자 (!, ++, --, +, -)

산술 연산자 (*, /, % 다음 +, -)

관계 연산자 (<, >, <=, >=)

관계 연산자 (==, !=)

논리 AND (&&)

논리 OR (||)

대입 연산자 (=, +=, -= 등)

예시
int x = 10, y = 5, z = 15;
bool result = x + y > z && z - y < x;
// 1. 산술 연산 먼저:
//    x + y  -> 10 + 5 = 15
//    z - y  -> 15 - 5 = 10
// 2. 관계 연산 다음:
//    15 > z -> 15 > 15 -> false
//    10 < x -> 10 < 10 -> false
// 3. 논리 AND 연산 마지막:
//    false && false -> false
std::cout << "복합 조건 결과: " << std::boolalpha << result << std::endl; // 출력: false

이처럼 괄호를 적절히 사용하여 연산 순서를 명확히 하는 것이 코드의 가독성을 높이는 데 매우 중요합니다.

아래 다이어그램은 비교식과 논리 연산자를 조합할 때 실수 비교, 단락 평가, 괄호 기준을 함께 점검하는 조건식 작성 흐름입니다.

복합 조건식은 계산, 비교, 논리 순서로 풀어 읽는다

산술식이 값을 만들고, 관계 연산자가 bool로 바꾸며, && 와 || 가 마지막에 조건을 조합합니다.

  1. 산술 계산

    * / + - 비교할 숫자나 값을 먼저 만듭니다.

  2. 크기 비교

    < > <= >= 각 비교식이 bool로 바뀝니다.

  3. 동등 비교

    == != 같음과 다름도 bool 결과를 만듭니다.

  4. AND 조합

    && 모든 조건이 참이어야 참입니다.

  5. OR와 괄호

    || ( ) 섞인 조건은 괄호로 의도 단위를 고정합니다.

  6. 예시 식 분해

    원래 식 x + y > z && z - y < x 입력 x = 10 , y = 5 , z = 15 기준값 산술 x + y = 15 , z - y = 10 숫자 관계 15 > 15 , 10 < 10 false, false 논리 false && false false

  7. 실수 비교

    a == b 보다 std::abs(a - b) < EPS 처럼 오차 범위를 둡니다.

  8. 단락 평가

    보호 조건은 && 의 왼쪽에 두어 위험한 접근을 먼저 막습니다.

  9. 괄호 기준

    && 와 || 가 섞이면 사람이 읽는 판단 단위마다 괄호를 씁니다.

아래 다이어그램은 조건식에서 자주 나오는 실수를 안전한 bool 표현으로 고치는 기준을 정리합니다.

위험한 조건식은 작은 bool 표현으로 고친다

조건식이 길어질수록 비교 하나가 어떤 bool을 만드는지 분리해 읽어야 대입 실수, 범위 실수, 단락 평가 순서 실수를 줄일 수 있습니다.

  1. 비교와 대입 구분

    == 는 질문이고, = 는 값을 넣는 동작입니다.

  2. 범위는 두 비교로

    수학식처럼 이어 쓰지 말고 두 bool을 && 로 묶습니다.

  3. 부정 범위 확인

    !(a && b) 와 !a && b 는 다른 조건입니다.

  4. 생략되어도 안전한가

    단락 평가로 오른쪽 표현식이 실행되지 않을 수 있음을 기준으로 순서를 잡습니다.