[C++] bool 변수는 항상 true 혹은 false 인가

일하다가 경험한 일이다. 동료가 실행이 이상하다며 같이 보자고 했다. bool 변수 하나가 visual studio watch 에서는 true 값을 갖는데 if 문에서 true 와 비교하는 쪽으로 가지 않았다. 예를 들면

void function(bool isValid)
{
    //isValid : IDE의 watch 창에서는 true 였다.
    if (isValid == true)
    {
    }
    else
    {
         // 이곳으로 온다!!!
    }
}

리빌드를 해봐도 IDE를 재시작해도 같은 결과였다. 혹시나 하여 함수에 bool 값을 넘긴 callstack을 따라 가며 watch를 봤지만1 계속 true 였다. 직접 이 1byte bool 변수의 메모리 값을 봤고 매우 놀랐다. 1 이나 0이 아니다!

보통, bool 변수에는 어떤 판정의 결과를 저장한다. int*변수 p 를 bool 변수 isNotNull 에 저장한다면 경고 2 가 발생하겠지만 p의 nullptr 여부에 따라 isNotNull이 true 또는 false 값을 갖는다.

000000007FFF3B3A  cmp         qword ptr [p],0  
000000007FFF3B40  je          wmain+49h (7FFF3B49h)  
000000007FFF3B42  mov         byte ptr [rsp+50h],1  
000000007FFF3B47  jmp         wmain+4Eh (7FFF3B4Eh)  
000000007FFF3B49  mov         byte ptr [rsp+50h],0  
000000007FFF3B4E  movzx       eax,byte ptr [rsp+50h]  
000000007FFF3B53  mov         byte ptr [isNotNull],al

p가 0이면 7FFF3B49h 로 점프, 1이면 7FFF3B42로 점프 각각 점프 한 다음 rsp+50h가 가리키는 영역에 0 또는 1을 저장. 이것을 eax 에 다시 저장한 후 isNotNull에 저장한다. (visual studio 2010 sp1, x64, debug build)

하지만 bool 값이 네트워크 버퍼에서 가져온 값이라면 어떨까? 1byte 를 읽어서 어떤 bool 변수 x에 강제로(?) 넣는다면, x 가 다른 bool 변수에 전달하는 값은 true or false 값이 아니다. x에 강제로 넣어진 값이 계속 전달된다. 아래는 이를 표현하고자 만들어본 코드다.

void function(bool result)
{
	if (result == true)
	{
		cout<<"hello"<<endl;
	}
	else
	{
		cout<<"world!"<<endl;
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	bool isValid;
	memset(&isValid, 11, sizeof(bool));

	bool next = isValid;
	function(next);

	return 0;
}

16번 라인에 의해 isValid 영역에는 11값이 저장된다. 이를 next에 다시 대입하지만 18번 라인은 어셈블리 코드로

000000007FFF3B36  movzx       eax,byte ptr [isValid]  
000000007FFF3B3B  mov         byte ptr [next],al  

이것 뿐이기 때문에 값을 복사만 한다. 하여 11 값을 갖는 isValid는 next 에 같은 값을 복사 result에도 11값을 넘겨준다. result는 3번라인에서 true 가 아니기 때문에 9번 라인으로 진행된다.

문제를 찾기 힘들었던 것 중 하나는 위의 코드를 예를 들자면 watch 창에서 result 값이 true 로 표시된 것이었다. 아마도 watch 에서는 값을 표시할 때 bool 변수의 값을 보여줄 때는 1byte의 값이 0이 아니면 true 로 표시하고, 0이면 false 로 표시하는 것으로 추정된다. 0 도 1도 아닌 값이라고 표시해주면 좋았을 텐데 그게 좀 아쉽네. watch 에서 해당 변수의 실제 값을 보려면 watch 이름을 result 가 아니라

*((char*)(&result)),d

로 변경해주면 된다.

  1. 어둠의 다크니스가 생각나는군 -_-; 운명의 데스티니
  2. warning C4800: ‘int *’ : forcing value to bool ‘true’ or ‘false’ (performance warning)

“[C++] bool 변수는 항상 true 혹은 false 인가”에 대한 3개의 생각

  1. 이런 경우도 있군요.

    boolean을 true와 비교하지 않아서 이런 문제가 생긴 적은 없지만 비교하는 코드를 보게 된다면 이 기억이 떠올라 살펴볼 것 같네요.

    공유 감샤감샤.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다