VC++에서 bool이 가지는 의미. :: 2007/04/25 08:05


C에는 없는데 C++에 있는것 중의 하나가 bool입니다. true, false를 표현하는데 사용하는 데이터 타입이죠. 그런데 요놈이 참 좋은거 같은데 귀찮습니다. 아래 코드를 vs .net 2003 이상의 컴파일러에서 컴파일을 하면 성능 경고가 발생합니다. C4800이죠. bool보다 큰 타입에서 변환을 하는 경우는 다 발생합니다. 왜 그럴까요?


궁금해서 어셈블리로 변환을 해보았습니다. 성능 경고가 뜰만하군요. ㅋ 한 바이트를 변환하기 위해서 0과 비교하고 그 결과를 취하고 있습니다.

; bool b = a;
cmp    DWORD PTR _a$[ebp], 0
setne al
mov    BYTE PTR _b$[ebp], al

귀찮은 성능경고를 피하기 위해서는 아래와 같은 편법을 써야 합니다. 변환이 아닌 비교를 한다고 컴파일러를 속이는 것이죠. 아래 코드를 디어셈 해보면 아시겠지만 위 코드랑 별반 차이가 없습니다.


이쯤되면 보통 많은 분들은 이렇게 말씀하십니다. bool이 비교를 할 때에 더 좋으라고 만든거다. 저런 황당한 식으로 변환하는 코드가 더 잘못된 것이다. 그럼 과연 bool은 int보다 비교에서 더 성능이 뛰어날까요. 당연히 아닙니다. 1바이트인 bool을 비교하기 위해서 컴파일러는 내부적으로 movzx를 사용해서 bool을 4바이트로 확장합니다. 그리고 0과 비교하죠. 1바이트 bool은 한 마디로 공간 외에는 어떠한 경우에도 이득이 없습니다. 왜냐하면 CPU가 지금은 8비트가 아니기 때문입니다. 32비트 CPU에서는 32비트 자료형이, 64비트 CPU에서는 64비트 자료형이 가장 효율적입니다. 왜냐하면 CPU가 그것들을 기본 단위로 취급하기 때문이죠.

그렇다면 똑똑한 사람들이 만드는 컴파일러는 왜 대부분 bool을 1바이트로 구현했을까요? 메모리를 아끼기 위해서 그랬을까요? 만약 그랬다면 적어도 저는 bool 사이즈를 4바이트로 만드는 옵션을 제공해야 했다고 생각합니다. 안타깝게도 VC++에는 그런 옵션이 없었습니다. 그렇다면 표준에서 1바이트로 만들어!!! 라고 말했을까요? 그런것도 아닙니다. 표준은 사이즈에 대해서 아래와 같이 언급하고 있습니다. char 사이즈 외에는 전부 implementation-defined입니다. 구현하는 사람 멋대로 만들면 되는 거죠.

sizeof(char), sizeof(signed  char)  and sizeof(unsigned char) are 1; the result of sizeof applied to any other fundamental  type (_basic.fundamental_) is implementation-defined. [Note: in particular,   sizeof(bool) and sizeof(wchar_t) are implementation-defined.15) ]

bool은 1바이트, int는 4바이트 이렇게 생각하면 일견 int가 엄청난 공간을 낭비하는 것 처럼 보입니다. 변수가 네 개가 되면 4 : 16이 되어 버리죠. 하지만 실제로는 이렇게 단순한 문제가 아닙니다. 여기서는 단순히 저장 공간을 비교한 것이기 때문이죠. 비교에 들어가는 코드 크기 까지 고려한다면 이렇게 단순하지 않습니다.

32비트 컴퓨터에서 int를 0과 비교하는데에는 cmp 명령어 하나로 4바이트가 소모됩니다. 하지만 bool을 false와 비교하는데는 movzx, test를 사용해야 하기 때문에 6바이트가 소모되죠. 즉 bool이 2바이트를 더 사용하는 것 입니다. 한 변수에 대해서 비교가 두 번 발생한다면 본전이고, 세 번 발생한다면 int가 2바이트를 절약하는 셈이 됩니다.

실제로 bool과 int의 사이즈 문제는 코드 공간과 저장 공간 사이의 절충 문제입니다. 엄청나게 많은 환경 변수를 bool로 저장하고 실제로 비교는 거의 하지 않는 경우와, bool 변수는 몇 개 안되지만 엄청 많이 비교하는 경우가 다르다는 것이죠. 전자가 bool이 유리하다면 후자는 int가 유리합니다. 그래서 똑똑한 개발자가 이런 것을 모두 고려해서 전자와 같은 결정을 했다고 가정해 봅시다. 그렇다면 각종 값을 변환해서 저장하는 과정에서 경고가 뜹니다. 후자와 같이 결정을 한 경우라면 bool 변수를 쓰고 싶지만 bool의 장점을 활용할 수 없다는 단점이 있죠. 이러한 문제점을 해결하기 위해서는 bool의 사이즈를 변경할 수 있는 컴파일러 옵션이 있어야 합니다.

bool이 단지 사이즈 이슈만 가지고 있는것도 아닙니다. 그 유명한 vector<bool> 이슈도 있죠. vector<bool>은 형태는 bool을 저장하는 컨테이너처럼 보이지만 실제로는 템플릿 특화로 비트셋을 사용해서 처리하도록 되어 있습니다. 모르고 사용했다간 낭패를 겪을 수 있죠. 이걸 왜 비트셋으로 특화했는지는 더더욱 이해가 되질 않습니다. ㅠㅠ

4바이트 옵션??
bool에 관한 컴파일러 옵션이 생기면 어떨까요? 좋을까요? 나쁠까요? 어떤 개발자는 4바이트로 쓰고, 어떤 개발자는 1바이트로 쓰고, 지옥같을 까요? 물로 모든 문제에는 일장일단이 있기 마련이지만 저는 그렇게 많이 혼란스럽다고 생각하진 않습니다. 좀 더 융통성이 있다고 생각합니다.

과거에 제가 사용했던 C++ Builder에 포함된 컴파일러는 enum 사이즈에 관한 옵션을 가지고 있었습니다. 빌더의 경우 enum을 기본적으로 1바이트를 사용하고 옵션을 켜면 4바이트로 조정할 수 있습니다. 그 당시 저희 회사는 Visual C++과 빌더를 혼용해서 사용했죠? 제가 행복했을까요? 최악이었습니다. 그 옵션을 몰랐을 당시에 빌더에서 Visual C++ DLL 함수만 호출하면 엉뚱해졌기 때문입니다. 나중에야 enum 크기가 다른것을 알게되었고 옵션을 통해서 조정할 수 있다는 것을 알았죠. 그것을 알기까지 애꿎은 디버깅만 엄청 했었죠.

앞선 사례에서 만약에 빌더에서 옵션을 제공하지 않았다면 저는 enum으로 된 코드를 모두 고쳐야 했거나 적어도 빌더용 헤더는 별도로 제작했어야 합니다. 하지만 옵션을 제공함으로써 헤더 변경 없이 문제를 해결할 수 있었죠. 반면에 Visual C++ 컴파일러는 사이즈에 관한 어떤 옵션도 제공하지 않습니다.

정성태님의 "VC++에서 bool이 가지는 의미."를 읽으시면 사이즈에 관한 좀 더 상세한 내용을 보실 수 있습니다. 정성태님의 글에도 나오지만 사실 제가 위에까지 쓴 내용은 좀 트리키합니다. 사실 이 주제는 아래 댓글을 달아주신 김형욱님께서 제시한 것 입니다. 강제 캐스팅을 해도 컴파일러가 경고한다는 것이었죠. 그래서 왜 그럴까? 하고 알아보던 차에 적게된 내용입니다. 저도 사실 이런 식의 분석을 그다지 좋아하진 않습니다. ㅎㅎ 대세에 큰 영향을 주는 것도 아니죠. ㅋ

결론,.. VC++에게 bool은 어떤 의미일까요???

제가 bool에 관해서 굉장히 냉소적으로 썼지만 사실 int로는 bool을 따라갈 수 없는 부분이 있긴 합니다. 바로 형식 안전성과 관련된 부분입니다. bool 자체가 원래 true, false만 저장할 수 있도록 만들어진 자료형이란 이야기죠. 아래 댓글에서 김형욱님께서 제시한 페이지에 자세한 설명이 있습니다. 간단하게 세 단계를 통해서 스스로 bool의 타입 안전성을 깨닫도록 하고 있습니다.


작위적으로 보이지만 위의 코드는 컴파일되지 않습니다. BOOL과 int가 동일하기 때문이죠. 이 문제는 BOOL을 enum으로 정의하면 해결할 수 있습니다.


C언어로 개발을 해 보신 분이라면 누구라도 겪었을 법한 문제입니다. 저 또한 저런 문제를 겪은 적이 있었죠. 그래서 저런 코드는 되도록 잘 사용하지 않습니다. if(b) 내지는 if(!b)로 사용하죠. 성공 코드가 ERROR_SUCCESS 같은 경우만 비교를 해서 사용합니다. 이 단계를 우아하게 통과하려면 BOOL을 클래스로 만들면 됩니다.


초특급 핵폭탄입니다. 저는 미처 몰랐던 부분이기도 하구요. 비교 변환의 결과가 bool이 된다는 것이죠. 첫 번째 제시된 문제같이 하면 이건 양쪽다 변환될 수 있게 됩니다. 클래스로 만들면 안되나요? 안됩니다. C++에서는 builtin 타입에 대한 오버로딩은 못합니다.


결론은 위 코드에서 BOOL이 출력되도록 할 수 없다는 겁니다. 그럴싸하게 이것을 해결할 수 있는 방법이 있을까요?



스폰서
글타래

  • 2주간 인기 글
  • 2주간 인기글이 없습니다.
Trackback Address :: http://jiniya.net/tt/trackback/489
  • VC++에서 bool이 가지는 의미.

    Tracked from AnyDragon's Tatter | 2007/04/25 03:40 | DEL

    이 포스트를 보고 제 후임들한테 보여주고 느끼는 바를 이야기 하라고 했었습니다.BOOL은 int형인데 bool은 1bit 형인데 MFC를 쓰는데 있어서는 int가 더 빠르다 어쩌다 이런 저런 이야기들이 나왔..

  • Gravatar Image.
    정성태 | 2007/04/24 16:41 | PERMALINK | EDIT/DEL | REPLY

    물론, 100% 의미 부여로는 부족하지만. 사이즈가 의미가 있는 경우도 있지 않을까 싶은데요.
    예를 들어, struct 의 경우에 bool 변수가 4개 있다면 4byte 정렬에 맞게 되지만, BOOL 이 4개면 16byte 가 되어버리죠. 클래스가 범람하는 C++ 세계에서는 확실한 차이가 될 것 같습니다. ^^

    또한, 나름대로는 형식 안정성에 대한 기능을 제공하겠지요. true/false 만 제한되어 있다는 것과 BOOL 의 int 에 대한 typedef 과는 차이가 있으니.

    어쨌든, 개인적으로도 꼭 bool 을 씁니다. BOOL 은 왠지 둔해 보이는 것 같애서... Win32 함수 처리 이외에는 의식적으로 안쓰게 됩니다.

    • Gravatar Image.
      codewiz | 2007/04/24 18:39 | PERMALINK | EDIT/DEL

      좋은 지적 감사합니다.
      저 또한 일바이트라도 아끼는 것이 좋다고 생각합니다.
      하지만 bool 문제의 경우 단순히 아낄 수 있는 성질의 것이 아니라고 생각됩니다. 일종의 트레이드 오프해야 하는 문제죠. 4바이트 옵션이 있었으면 좋겠다고 생각한 것도 그래서입니다.

      사이즈에 관한 부연 설명은 글에다 추가했습니다.

  • Gravatar Image.
    김형욱 | 2007/04/24 23:21 | PERMALINK | EDIT/DEL | REPLY

    http://www.glenmccl.com/bool_cmp.htm

    생각나서 멤 도서관와서 찾아봤는데 예전에 본걸 못찾겠넹...

    인터넷 뒤지다가 글 하나 있어서 주소 올린다...

    언제쯤 너의 지식의 깊이를 따라잡을 수 있을지.. ㅋ

    • Gravatar Image.
      codewiz | 2007/04/25 08:08 | PERMALINK | EDIT/DEL

      제가 미처 몰랐던 부분이 있었네요. f(3<4)에서 화들짝 놀랐습니다. 심오하군요. ㅋㅋ 당연한 건가???? 흐흐~~

      그런데 읽다보니 마지막 단계를 통과할 수 있는 코드를 만들 수 있을까가 궁금해지네요. 점점더 geek해집니다. ㅋㅋ

  • Gravatar Image.
    정성태 | 2007/04/25 09:10 | PERMALINK | EDIT/DEL | REPLY

    그렇군요. f(3<4) 과 같은 문제가 있군요. 일단 typedef 은 undef 이 안되니. 만에 하나 그것이 반드시 필요한 경우라면,,, 다음과 같은 식으로만 해결할 수 있지 않을까 싶네요. (사실, "우아한" 방법이야 컴파일러 표준차원에서의 지원이 되어야 하겠지만. ^^)

    #define BOOL nothing
    typedef bool BOOL;

    void f(BOOL b) { printf( "BOOL\n" ); }
    void f(int b) { printf( "int\n" ); }

  • Gravatar Image.
    drvoss | 2007/04/25 18:57 | PERMALINK | EDIT/DEL | REPLY

    f(3<4).. 정말 그렇네요. 마치 법적으론 아무 하자 없지만, 도덕과 예절과 문화상 그렇게 하면 안되는게 당연한것같은 느낌입니다. 옵션으로 4byte로 변환하게 되면 0x00000001과 0x00000000의 값으로 바뀌는 건가보네요.

    델파이의 Boolean 같은경우 VC의 bool로 받아야 되던데, 임플리먼테이션 디파인드 보다 스펙 쪽에서 정해 줬으면 깔끔했을껄 하네요.

    • Gravatar Image.
      codewiz | 2007/04/25 19:50 | PERMALINK | EDIT/DEL

      스펙으로 정해버리면 혼란이 업긴한데 효율성이 떨어진다는 단점이 있죠. 특히나 스펙같은 경우는 한번 정해버리면 자주 바꾸기가 어렵기 때문에 그런 문제가 더 심각한 것 같습니다. 참. 어려운 문제같아요. *^^*

  • Gravatar Image.
    achoura | 2021/06/10 04:08 | PERMALINK | EDIT/DEL | REPLY

    Magnificent goods from you, man. I’ve bear in mind your stuff prior to and you’re just extremely great.

Name
Password
Homepage
Secret