본문 바로가기

C에도 Boolean 타입이 있다?

기술적인 이야기/잡다한 기술적인 이야기 2023. 2. 2.
반응형

C 언어는 너무도 오래전에 탄생한 탓일까? 이진(boolean) 타입, 즉 참(true)과 거짓(false)을 표현하기 위한 데이터 타입이 존재하지 않는다. 아 물론 개인적인 기억 속의 이야기다.

하지만 최근에는 이상한 이야기를 들었다. C 언어에도 boolean 네이티브 타입이 존재한다는 소리 말이다. C 언어를 다뤄본지는 좀 오래된 너무나 구식 인간이었던 나는 이게 도대체 무슨 소리인지 몰랐다.

C에는 bool, true, false가 원래 없었다

전통적으론 거짓

전통적인 C 언어를 생각해 보면 원시 타입(primitive types, 언어에 따라 builtin types)에는 참과 거짓을 표현하는 특수한 타입은 존재하지 않는다. 대신 숫자로 0은 거짓, 그 외의 값은 참의 의미로 쓰도록 설계된 언어다. 현재도 if 문의 조건에는 수식으로 0 이외의 값은 참이 된다. 거기다 값이 없다는 의미인 NULL은 숫자 0의 매크로다.

대신 C 언어는 매크로 활용이 무궁무진하다. 즉 필요하다면 전처리기 매크로를 활용해서 이진 타입을 정의해서 사용하는 방법이 많이 쓰여왔다.

#define bool  unsigned char
#define true  ((unsigned char)1)
#define false ((unsigned char)0)

bool is_odd(int value) 
{
    if (value % 2 == 0) {
        return false;
    } else {
        return true;
    }
}

이렇게 해서 bool 이라는 이름은 가장 작게 표현되는 바이트 타입인 unsigned char 타입으로 쓸 수 있게 된다. 물론 대체 타입은 마음대로 쓸 수 있다. char, int 등 사실상 포인터를 제외한 모든 타입을 쓸 수 있다.

물론 완벽한 지원은 아니지만 지극히 전통적으로 C 언어 다운 방식이다.

반응형

계속 발전하는 입장에선 참

C 언어도 계속 발전하며 버전이 올라가고 있다. 덕분에 C99 표준부터는 _Bool 타입이 생겼다. 이 이름은 가독성이 영 좋지 못 하지만 어쨌든 의미가 통하며 별도의 헤더 추가 없이 원시 타입과 비슷하게 그대로 쓸 수 있다. 이 타입의 크기는 macOS에서 측정할 경우 1 바이트로 char 타입의 매크로 같지만 시스템이나 구현체에 따라 다를 수도 있다.

다만 값으로는 여전히 별도의 이름 없이 0과 1을 사용해야 한다. 그렇다고 이름 없이 쓰긴 좀 그런데 위의 매크로로 정의해서 쓰라는 것일까?

다행히도 개발자에게 조금은 더 편하라고 stdbool.h에서 좀 현대적인 이진 타입을 재정의 해주고 있다. bool, true, false라는 이름 말이다. 그래서 이 헤더를 추가한 후 위의 예제처럼 그대로 사용할 수 있다.

#include <stdbool.h>

bool is_odd(int value) 
{
    if (value % 2 == 0) {
        return false;
    } else {
        return true;
    }
}

앞서 매크로로 정의한 bool이나 true, false와 사실상 동일하게 사용할 수 있다. 물론 C99를 지원하는 컴파일러여야 되겠지만 말이다.

사심

근데 도대체 무슨 차이가 있는 걸까? 어차피 기존에도 매크로를 정의해서 쓸 수 있었고 이젠 stdbool.h를 이용하면 약간의 수고를 덜어줄 뿐이다. 결과적으로 바뀐 건 거의 없다. 그저 표준으로 _Bool이 추가된 것일 뿐이다. 내 코드가 바뀐 건 전혀 없다. 동작하는 방식이 바뀐 것도 없다.

거기다 독특한 문제도 하나 더 있다. 안타깝게도 stdbool.h 헤더에 정의된 bool 심볼은 매크로로 정의된 이름일 뿐이지 원시 타입이 아니다. 이 말은 stdbool.h 헤더를 포함시키지 않으면 아래의 코드는 제대로 동작하지 않는다는 말이 된다.

#if true
    ...
#endif

위의 #if 블럭 내부는 실행되지 않는다. 왜냐하면 true가 정의되어 있지 않기 때문이다. 물론 stdbool.h 헤더를 추가한 후에는 원하는 대로 동작한다.

심지어 true는 1의 매크로이고, false는 0의 매크로다. 이 말은 참과 거짓을 특정 숫자와 비교할 수 있다는 어이없는 행위도 가능하게 한다.

그렇다면 표준으로 이진 타입이 생긴 것과 생기지 않은 것의 차이는 도대체 무엇일까? 적어도 나는 표준이라면 별도의 include 절차는 필요 없는 수준이 되어야 하지 않을까 생각된다. 그래서 이게 과연 네이티브 지원인가 심각한 고민을 하게 만드는 것 같다. 물론 개인적인 생각일 뿐이다.

728x90
반응형

댓글