노무현 전 대통령 서거 추모글 남기기

퍼온 곳:  http://cafe.naver.com/applekoong/379


부울(G. Boole, 1815~1864)이라는 수학자가 있었답니다.

언제적 인물인지도 모르는 수학자가 만든 참과 거짓을 이용한 계산식을 부울 대수(Boolean Algebra)라고 부릅니다.

프로그래머에게는 부울 대수보다는 진리표(truth table)라는 이름이 친근합니다.

진리표가 어렵다면 논리 연산은 어떨까요?

한 가지 사물을 여러 가지 방법으로 부르는 것뿐입니다.

 

[참과 거짓에 대한 정의]

거짓, FALSE - 0

참, TRUE - 0이 아닌 모든 값

 

흔히 하는 실수로 참(TRUE)을 1로 생각하는 경우가 있습니다.

대부분 1이지만, 경우에 따라 1이 아닌 2가 될 수도 있고 -1이 될 수도 있습니다.

그러면 왜, 참을 이와 같이 복잡하게 정의한 것일까요?

실제로는 복잡하게 정의한 것이 아니라 안전하게 정의했다고 표현하는 것이 맞습니다.

 

일단 거짓(FALSE)은 "존재하지 않는다"라는 정도로 해석할 수 있기 때문에,

같은 의미를 갖는 숫자인 0을 사용합니다.

음수인 경우는 음수 크기만큼 갖는다고 얘기합니다.

0일 때 더함도 덜함도 없이 없는 것입니다.

 

만약 참을 1로 정의하면 어떤 일이 일어날까요?

참과 거짓을 알려주기로 약속을 해놓고,

상대방이 이도저도 아닌 -1을 주었습니다.

내 프로그램은 이때 어떻게 동작할까요?

현실에서 이와 같이 예상할 수 없는 일이 일어나면

여러분은 어떻게 행동합니까?

그렇습니다. 깜짝 놀라 당황합니다.

프로그램은?

마찬가지로 깜짝 놀라 당황하고, 비정상적으로 종료하게 될 것입니다.

 

비정상 종료가 발생하게 된 근본 원인은

참과 거짓에 대한 정의를 벗어날 수 있는 숫자가 있다는 것을 인정하지 않았다는 것입니다.

약속은 약속일 뿐이고, 언제든 약속을 어길 수가 있기 때문에 그에 대한 대비를 해야 합니다.

참과 거짓의 경우는 모든 숫자를 참과 거짓으로 나누어야

처리에 어떤 장애도 갖지 않을 수 있습니다.

 

모든 숫자에 대처하기 위해

거짓은 0이고, 참은 거짓이 아닌, 즉 0이 아닌 모든 숫자가 됐습니다.

이제 어떤 숫자가 와도 참과 거짓으로 판단할 수 있게 되었습니다.

 

[함수 반환값에서 주의할 점]

보통 참과 거짓을 함수에 대해 사용하는 경우에는

성공과 실패를 의미할 때가 많습니다.

참은 성공, 거짓은 실패를 의미합니다.

이와 같은 유형의 함수의 반환값은 두 가지가 있습니다.

 

    1. 진짜 참과 거짓을 반환하는 함수

    2. 0과 0이 아닌 정수를 반환하는 함수

 

두 가지 모두 실패는 0을 나타내고 상수로 표현하면 FALSE가 됩니다.

그러나, 참인 경우에는 서로 다릅니다.

1번은 진짜 참을 반환하기 때문에 1을 반환하지만,

2번은 0이 아닌 정수라고 표현했기 때문에 2나 3을 반환할 수도 있습니다.

이러한 함수에서 다음과 같은 코드는 재앙을 초래할 수 있습니다.

 

    if( ReturnValue == 1 )

        printf( "함수 성공" );

 

함수가 반환한 값이 1일 수도 있겠지만,

누차 얘기하듯이 2나 3일 수 있습니다.

그러면 2나 3은 성공이 아닙니까?

성공 맞습니다. 그러나, 성공에도 등급이 있을 수 있지 않습니까?

돈을 많이 버는데, 많이 버는 정도가 서로 다르다는 말입니다.

성공에 대해 0이 아닌 정수를 반환하는 경우는

성공을 여러 가지 형태로 나누길 바라기 때문입니다.

 

어떤 경우는 실패를 단순히 0이 아니라

여러 가지 경우로 나누어 처리하기도 합니다.

주로 음수를 사용해서 표현하는데,

-1은 이름을 잘못 사용했다던가

-2는 파일을 열 수 없었다던가 등등

실패의 종류를 구분하고 싶을 때가 있습니다.

 

    if( ReturnValue != 0 )

        printf( "함수 성공" );

 

제대로 표현하려면, 항상 거짓을 의미하는 0과 비교하는 습관을 들이는 것이 중요합니다.

거짓의 값은 0, 하나뿐이기 때문에 어떤 값을 반환하더라도 성공한 경우에 대처하게 됩니다.

 

[참/거짓과 조건]

참과 거짓은 제어문과 반복문에 이는 조건문에서 주로 사용합니다.

성공과 실패를 판단해서 각각에 맞는 처리를 해야 하므로

조건문과 뗄레야 뗄 수 없는 관계를 맺게 됩니다.

 

그러면 조건문에서 거짓으로 판단하는 0의 값을 갖는 경우에는 어떤 것들이 있을까요?

 

1. 정수 - 0

2. 실수 - 0.0

3. 문자 - 0('\0')

4. 포인터 - 0(NULL 포인터)

 

메모리 관점에서 봤을 때,

비교하고자 하는 메모리의 모든 비트가 꺼져 있을 때를 0으로 간주하는데,

자료형에 따라 해석이 달라집니다.

정수는 0, 실수는 0.0이 되는 것처럼,

문자인 경우에는 null문자, 포인터라면 NULL 포인터가 됩니다

(0번지를 가리키는 주소가 아니라 가리키지 않는다는 뜻의 NULL 포인터입니다.).

이때 포인터의 종류는 상관없습니다.

int*, char*, 구조체 포인터 등등 모든 포인터가 가리키는 곳이 없으면 NULL 포인터가 됩니다.

 

[BOOL vs. bool]

참과 거짓을 나타내는 방법이 C와 C++에서 다릅니다.

C 언어는 대문자 BOOL 자료형을 사용하고

C++는 소문자 bool 자료형을 사용합니다.

둘 다 참과 거짓을 표현하기 위해 만들었지만, 내부는 완전히 다르고 호환되지 않습니다.

 

일단 BOOL 자료형이 C 언어에는 없습니다.

대문자 BOOL 자료형을 사용하려면 typedef를 통해 재정의해야 합니다.

 

    typedef  int  BOOL;

 

이제 int와 BOOL은 같은 자료형이 되었고, BOOL 자료형을 사용할 수 있습니다.

문제는 BOOL 자료형의 근본이 int 자료형이기 때문에

2나 3의 값도 잘 받아들인다는 것입니다.

앞서 말했듯이 항상 거짓인 0과 비교해야 하는 이유입니다.

여기에 대문자 TRUE와 FALSE를 사용하기 위해 enum이나 define으로 상수를 정의합니다.

 

    #define  FALSE  0

    #define  TRUE    1

 

아니면

 

    enum { FALSE, TRUE };

 

처럼 사용해도 됩니다.

다만 정수에 대해서만 정의했고, 둘 다 int 상수라는 점입니다.

자료형과 값을 따로따로 설정하는 것이 번거로워서

다음처럼 한번에 처리하기도 합니다.

 

    typedef enum { FALSE, TRUE } BOOL;

 

그러나, 여전히 BOOL 자료형의 근본이 int 자료형이라는 것에는 변함이 없습니다.

 

    BOOL sw = -1;

 

에러나지 않는 코드입니다.

-1을 의도적으로 넣는 분은 없겠지만,

실수했을 때 컴파일러가 잡아주지 않기 때문에

나중에 치명적인 버그로 나타납니다.

C++인 경우에는 이 코드에서 FALSE와 TRUE만 사용해야 에러가 나지 않습니다.

 

C++에서는 참과 거짓에 대한 단점을 보완하기 위해

C 언어에 없는 새로운 자료형은 제공했는데, 그게 소문자 bool 자료형입니다.

 

    bool sw = -1;

 

이제 이 코드는 에러입니다.

bool 자료형에는 소문자 true와 false만 넣을 수 있습니다.

그러나, VC++ 6.0에서는 에러가 발생하지 않고,

닷넷 컴파일러에서는 가벼운 에러를 뜻하는 경고(warning)가 뜹니다.

true와 false만 넣기 위해 만든 자료형에 -1을 넣는다는 것이

무슨 뜻인지 알 수 없기 때문에, 경고를 발생시키는 것이 맞습니다.

 

BOOL 자료형과 TRUE, FALSE 상수를 정의했다고 가정합니다.

 

    BOOL sw1 = TRUE;

    BOOL sw2 = true;            // VC++ 6.0에서 에러

    bool sw3 = TRUE;

    bool sw4 = true;

 

6.0에서는 에러가 발생하지 않아도 될 부분에서 에러가 발생합니다.

bool 자료형의 크기는 1바이트로,

정확하게 0과 1을 표현하기 때문에 1바이트 정수를 4바이트 정수에 넣는 코드에서 에러가 발생하고 있습니다.

닷넷 컴파일러에서는 전혀 에러가 발생하지 않습니다.

분명 BOOL과 bool 자료형은 다른 자료형임에도

컴파일러 내부적으로 0과 1의 값을 갖는지 판단하는 것 같습니다.

sw3과 sw4에 0과 1이 아닌 값을 넣으면 경고가 뜹니다.

상수로 정의하지 않더라도 0과 1을 넣으면 문제가 없습니다.

표준은 아니지만, 컴파일러 확장 옵션이라고 생각됩니다.

 

[boolean 자료형과 라이브러리]

리눅스와 윈도우 프로그래밍, 즉 C 언어를 벗어나서 운영체제에 특화된 코딩을

시스템 프로그래밍이라고 부릅니다.

윈도우에서는 Win32 API 프로그래밍이라고 부르고,

리눅스에서는 정직하게 시스템 프로그래밍이라고 부릅니다.

 

운영체제를 C 언어로 만들었다고 하는 것은

C++에서 제공하는 bool 자료형을 API에서 볼 수 없다는 것을 뜻합니다.

파일 확장자를 cpp로 주면,

여러분은 bool 변수를 만들어쓸 수는 있지만,

성공 여부를 반환하는 시스템 함수(API)는 대문자 BOOL을 반환할 거라는 뜻입니다.

컴파일러에 따라, 앞서 설명처럼 경고 또는 에러가 발생하겠지만

호환되지 않을 수 있다는 사실을 인지하고 있으면,

형변환이라도 해서 사용할 수 있겠습니다.

 

당연히 C++ 라이브러리에서는

성공 여부를 반환하는 함수는 bool 자료형을 반환합니다.

STL에 들어있는 컨테이너의 멤버 함수인 empty()는

비어있을 때 true, 비어있지 않을 때 false를 반환합니다.

C 언어는 아쉽게도 BOOL 자료형조차 정의하지 않고 있기 때문에

0과 1을 반환할 것입니다.

 

저는 가능하면 bool 자료형을 사용하려고 노력합니다.

잘못될 수 있는 여지를 막아주고 있는데,

사용하지 않는다면 그게 오히려 이상하다고 생각합니다.

라이브러리와 충돌이 나는 부분은 형변환을 통해서 처리합니다.

namespace, 참조 변수 등등 C 언어에 없는 많은 개념을 저는 사용하고 있습니다.

조건 비교에서 true와 비교할 수 있다는 것만으로도 가치가 있다고 생각합니다.

 

강요하는 것은 아니고

어떤 자료형을 쓸지는 여러분이 직접 결정해야 합니다.

저는 여러분이 선택할 수 있도록 정확한 정보를 제공할 뿐입니다.

Posted by Kelly Cook
,