안녕하세요. 언제나 휴일에 언휴예요.
이번 강의는 논리 형식과 논리 연산을 다룰 거예요.
1. 논리 형식 2. 논리 값, 참과 거짓 3. 논리부정(NOT) 연산자는 ! 4. 논리곱(AND) 연산자는 &&, 논리합(OR) 연산자는 || 5. 논리 연산에서 주의할 점 1 6. 논리 연산에서 주의할 점 2
1. 논리 형식
C언어에는 논리 형식을 제공하지 않아요.
대신 기본 형식(char, short, int, long, float, double 등)과 메모리 주소처럼 수로 나타낼 수 있는 것은 모두 논리 형식으로 사용할 수 있습니다.
이번 강의를 통해 피 연산자로 다양한 형식을 사용할 수 있다는 것을 느낄 수 있었으면 합니다.
2. 논리 값, 참과 거짓
C언어는 논리 형식을 제공하지 않습니다.
논리 리터럴 표현도 제공하지 않습니다.
그렇지만 C언어에서는 0을 거짓으로 취급하며 0 이외의 모든 값을 참으로 취급합니다.
이러한 약속은 이번 강의를 통해 알 수 있을 거예요.
3. 논리부정(NOT) 연산자는 !
C언어에서 제공하는 논리 연산자는 &&(논리곱, AND), ||(논리합, OR), !(논리부정, NOT)을 제공합니다.
먼저 논리부정(NOT) 연산자인 !을 사용해 봅시다.
C언어에서 연산 결과가 참이면 1, 거짓이면 0입니다.
먼저 다양한 값을 전달한 후에 논리부정 연산을 한 결과를 확인해 볼게요.
#include int main() { char c = 'a'; short s = 2; int i = 4; float f = 0.1f; double df = 0.2; printf("%d %d %d %d %d\n", !c, !s, !i, !f, !df); return 0; }
컴파일 오류가 없는 것을 보면 사용한 형식들은 논리부정 연산에 피연산자로 사용할 수 있다는 것을 알 수 있어요.
다음은 실행 결과예요.
0 0 0 0 0
앞에서 C언어에서는 0을 제외한 모든 값은 참이라고 얘기했어요.
그리고 연산 결과가 참이면 1, 거짓이면 0이라고 얘기했지요.
위에서 사용한 예는 모든 변수의 값이 0이 아니므로 참입니다.
그리고 논리부정 연산을 수행한 결과는 모두 거짓이므로 출력 값이 모두 0인 거예요.
이번에는 세 개의 변수에 0을 설정한 후에 논리부정 연산을 해 볼게요.
#include int main() { char c2 = 0; int i2 = 0; double df2 = 0; printf("%d %d %d\n", !c2, !i2,!df2); return 0; }
실행 결과는 다음과 같습니다.
1 1 1
0은 거짓이라고 했었죠. 그리고 연산 결과가 참이면 1이라고 했어요.
따라서 0(거짓)의 논리부정 연산한 결과는 참인 1입니다.
4. 논리곱(AND) 연산자는 &&, 논리합(OR) 연산자는 ||
논리곱(AND)연산은 피연산자가 모두 참일 때만 연산결과가 참이죠.
논리합(OR)연산은 피연산자가 모두 거짓일 때만 연산 결과가 거짓이죠.
다음의 코드처럼 다양한 형식에 다양한 값으로 논리곱과 논리합 연산을 수행해 보세요.
#include int main() { char c = 'a'; short s = 2; int i = 4; float f = 0.1f; double df = 0.2; char c2 = 0; int i2 = 0; double df2 = 0; printf("test1:%d\n", c && s); printf("test2:%d\n", c && i2); printf("test3:%d\n", c2 && f); printf("test4:%d\n", c2 && df2); printf("=============\n"); printf("test5:%d\n", i || df); printf("test6:%d\n", i || df2); printf("test7:%d\n", c2 || f); printf("test8:%d\n", i2 || df2); return 0; }
컴파일하면 아무런 오류가 없는 것을 보면 역시 논리연산에는 수를 표현할 수 있는 다양한 형식이 올 수 있다는 것을 알 수 있어요.
실행 결과를 봅시다.
test1:1 test2:0 test3:0 test4:0 ============= test5:1 test6:1 test7:1 test8:0
결과를 보면 논리곱은 둘 다 참일 때(test1)만 연산 결과가 1입니다.
논리합은 둘 다 거짓일 때(test8)만 연산 결과가 0입니다.
이를 통해 C언어에서는 연산 결과가 참일 때 1, 거짓일 때 0임을 보다 명확히 알 수 있어요.
5. 논리 연산에서 주의할 점 1
논리 연산에서 주의할 점은 논리곱과 논리합 연산자는 하나의 토큰으로 뗄 수 없는 거예요.
따라서 중간에 공백이 오면 문법적 오류입니다.
다행인 것은 문법적 오류가 있는 코드는 컴파일해주지 않는다는 것이죠.
개발 단계에서 명확하게 알 수 있어요.
처음 익힐 때는 이러한 오류가 긴장하게 만들고 위축시키지만 개발자에게 도움을 주는 메시지예요.
나타난 현상을 인정하고 문제를 해결하고자 하는 자세가 필요할 뿐이죠.
위 그림을 보면 29번 줄에 && 연산자 사이에 공백이 있어서 발생한 오류예요.
무자비하게 여러 개의 오류가 잇는 것처럼 보이지만 공백 하나 때문에 나온 메시지들입니다.
오류 메시지가 나오면 맨 위에 발생한 오류부터 해결해 나가세요. 여러 개의 오류 메시지가 나왔다고 정말 여러 곳을 고쳐야 하는 것은 아닙니다.
반대로 하나의 오류가 발생하여 고쳤을 때 더 많은 오류가 발생할 수도 있어요. 이 또한 원래 해결해야 할 오류이므로 겁 먹지 마시고 하나 하나 해결해 나가세요.
6. 논리 연산에서 주의할 점 2
논리 연산자 사이에 공백을 집어 넣어서 발생하는 오류는 개발 단계에서 빠르게 확인이 가능하죠.
오류가 나와서 고치지 않으면 컴파일을 못하니까요.
문법 오류보다 어려운 것은 논리적 버그예요.
문법에는 문제가 없지만 개발자의 코드에 논리가 문제가 발생하는 것이죠.
마지막으로 논리 연산자에서 주의해야 할 논리를 얘기할게요.
논리곱 연산은 좌측 피연산자가 거짓이면 우측 피연산자를 확인하지 않아요.
논리합 연산은 좌측 피연산자가 참이면 우측 피연산자를 확인하지 않아요.
이 얘기는 처음 시작하는 분들에게 어려울 수도 있어요.
그럼에도 설명을 보시고 이해를 못하겠으면 다음에 다시 한 번 살펴보세요.
다음 코드를 먼저 보시죠.
#include int main() { int re1 = 1; int re2 = 1; (re1 = 0) && (re2 = 0); printf("re1:%d re2:%d\n", re1, re2); return 0; }
실행 결과는 다음과 같습니다.
re1:0 re2:1
논리곱 연산의 왼쪽 피연산자는 re1=0을 대입한 결과, 0입니다.
거짓이죠.
논리곱 연사의 왼쪽 피연산자가 거짓이면 우측 피연산자를 보지 않습니다.
따라서 (re2=0) 부분은 수행하지 않는 거예요.
이러한 이유로 re1은 0이지만 re2는 여전히 1입니다.
다음 코드의 실행 결과를 예측해 보세요.
#include int main() { int re1 = 1; int re2 = 1; (re1 = 2) && (re2 = 0); printf("re1:%d re2:%d\n", re1, re2); return 0; }
실행 결과는 다음과 같습니다. 예측 결과가 다르다면 다시 한 번 생각해 보세요.
re1:2 re2:0
이번에는 논리곱 연산의 왼쪽 피연산자는 re1=2를 대입한 결과, 2입니다.
참이죠.
논리곱 연산의 왼쪽 피연산자가 거짓일 때만 우측 피연산자를 보지 않는다고 했어요.
따라서 이번에는 우측 피연산자도 수행합니다.
이번에는 논리합 연산에 관한 코드를 살펴볼게요.
논리합 연산은 왼쪽 피연산자가 참이면 우측 피연산자를 보지 않는다는 점을 기억하세요.
#include int main() { int re1 = 1; int re2 = 1; (re1 = 2) || (re2 = 0); printf("re1:%d re2:%d\n", re1, re2); return 0; }
실행 결과는 다음과 같습니다.
re1:2 re2:1
이번에는 논리합 연산의 좌측 피연산자가 참이어서 우측 피연산자를 수행하지 않았어요.
마지막 코드를 보고 예측해 보세요.
#include int main() { int re1 = 1; int re2 = 1; (re1 = 0) || (re2 = 0); printf("re1:%d re2:%d\n", re1, re2); return 0; }
실행 결과는 다음과 같아요.
re1:0 re2:0
이번에는 논리합 연산의 좌측 피연산자가 거짓이므로 우측 피연산자를 수행한 것이죠.
이와 같은 논리적 버그는 초보 개발자 뿐만 아니라 숙련자도 부담스러운 존재예요.
10분 동안 하나의 문제를 해결하지 못할 때 잠시 커피나 바람을 쐬는 것을 추천합니다.
물론 해결하기 위해 최선을 다 하는 것이 우선이겠죠.
이번 강의에 마지막 부분이 여러분에게 좌절이 아닌 도전이 되길 빌게요.