C 언어를 처음 접하고 코딩을 시작하면 상당히 헷갈리는 부분이 생깁니다.
그 대표적인 예가바로 & 와 && 그리고 | 와 || 입니다.
둘 다 AND 와 OR 연산임은 맞는데 뭐가 다를까요?
먼저 & 와 | 는 비트 연산자이고,
&& 와 || 는 논리 연산자입니다.
정확히 설명을 하자면,
& 는 특정 변수를 각 비트별로 AND 연산을 하여 그 값을 도출해 내는 것이고,
&& 는 변수의 값 자체의 논리 값을 AND 연산해 결과 값 또한 논리 값으로 표현 됩니다.
따라서 비트 연산과 논리 연산은 그 용도가 다릅니다.
& 는 비트단위로 사칙연산과 같은 값의 계산을 위해 사용되고,
&& 는 True / False 를 구분 하기 위해 사용됩니다.
먼저 비트연산을 알아보겠습니다.
비트 연산을 이해 하기 위해서는 비트가 무엇인지 알아야 겠지요.
비트는 데이터를 저장 할 수 있는 최소의 단위 입니다.
저장한다는 것은 컴퓨터가 메모리에 데이터를 기억 한다는 뜻이며, 그 데이터의 형태를 0 과 1 로만 표현 했다는 겁니다.
그럼 0 과 1을 메모리에 어떻게 적을까요? 연필로 쓰지는 않겠지요?
바로 전기가 통하는 상태와 전기가 통하지 않는 상태를 각각 1 과 0 으로 정의 합니다.
정확히는 특정 전압 이상( 메모리마다 다르며 메모리를 구성하는 래치의 상태를 High 상태로 만들 수 있는 트랜지스터 베이스단자의 입력 전압) 일때를 1, 그 이하일때를 0 이라 정의 합니다.
그렇다면, 0 과 1 만으로 어떻게 숫자 5를 표현 할까요?
이것을 이해하기위해 '진수법' 을 알아야 합니다.
0 과 1 만 가지고 데이터를 표현 하는 방법을 '2진법'이라고 합니다.
그럼 우리가 흔히 쓰는 숫자의 진수법은 무엇일까요?
바로 10진법 입니다.
먼저 2 진법으로 숫자 0~ 3 까지 표현을 시도해 보겠습니다.
2 진법 | 10 진법 |
0 | 0 |
1 | 1 |
? | 2 |
숫자 3을 표현 할 수 가 없군요.
이래서 1 비트로는 2가지의 데이터면 표현 할 수 있습니다.
그렇다면 그 이상의 데이터는 어떻게 표한 할까요?
바로 비트를 연결해서 사용 하면 됩니다.
2 진법 | 10진법 |
00 | 0 |
01 | 1 |
10 | 2 |
11 | 3 |
?? | 4 |
두 개의 비트를 연결해 데이터를 표현 했더니 10 진수의 0~3 까지 총 4 개의 값을 표현 할 수 있습니다.
그렇다면 이 비트의 수가 많아질 수록 표현 가능한 숫자의 크기도 달라지겠지요.
2 진법 | 10 진법 |
0000 | 0 |
0001 | 1 |
0010 | 2 |
0011 | 3 |
0100 | 4 |
0101 | 5 |
... | |
1111 | 15 |
4비트 데이터로 표현 가능한 숫자는 0~15 까지 이고, 그 갯수가 16개입니다.
그런데 여기서 한 가지 문제가 있습니다.
바로 2 진법으로 표현된 숫자는 10 진법으로 쉽게 파악되지 않는다는 것입니다.
하지만 아래 표와 같이 16진법을 사용하면 비트(2진법)으로 표현된 데이터의 가독성이 매우 높아집니다.
2 진법 | 16 진법 | 10 진법 |
0000 0000 | 0x00 | 0 |
0000 0001 | 0x01 | 1 |
0000 0010 | 0x02 | 2 |
0000 0011 | 0x03 | 3 |
0000 0100 | 0x04 | 4 |
0000 0101 | 0x05 | 5 |
0000 0110 | 0x06 | 6 |
0000 0111 | 0x07 | 7 |
0000 1000 | 0x08 | 8 |
0000 1001 | 0x09 | 9 |
0000 1010 | 0x0A | 10 |
0000 1011 | 0x0B | 11 |
0000 1100 | 0x0C | 12 |
0000 1101 | 0x0D | 13 |
0000 1110 | 0x0E | 14 |
0000 1111 | 0x0F | 15 |
0001 0000 | 0x10 | 16 |
0001 0001 | 0x11 | 17 |
0001 0010 | 0x12 | 18 |
0001 0011 | 0x13 | 19 |
0001 0100 | 0x14 | 20 |
. . . | . . . | . . . |
참고 : 16 진수 앞에 붙은 "0x" 는 16 진수 임을 나타내는 표시 입니다.
위 그림과 같이 2 진수를 16진수로 표현 했을때 자리 올림의 형태가 4비트 단위로 맞아떨어져 매우 가독성이 좋습니다.
따라서 컴퓨팅의 모든 데이터는 2 진수로 저장되고, 계산은 16진수로 표현합니다.
어쨌든,
비트연산은 이처럼 몇 개의 비트로 구성된 데이터를 서로 더하거나 빼거나 반전 시키는 등의 연산을 하는 것을 말합니다.
그중 & 는 이 비트들을 자릿수별로 곱한 것과 같습니다.
연산 기호 & 는 논리 연산 게이트 AND 와 같은 계산입니다.,
예를들어 다음 코드를 보겠습니다.
#include <stdio.h>
void main(void)
{
int a, b, c;
a = 0x0A;
b = 0x0E;
c = 0;
c = a&b;
printf("c = %d[0x%x]\n",c,c);
}
위 코드의 결과는 아래와 같습니다.
c = 10[0xa]
이것은 실제 회로적으로 아래 그림과 같은 로직을 거치게 됩니다.
변수 a 에 저장된 값 0x0A 는 2 진수로 1010 이고,
변수 b 에 저장된 값 0x0E 는 2 진수로 1110 입니다.
이 두 변수를 & 연산 하게 되면 각 비트별로 AND 게이트를 거치게 됩니다.
각 비트별 AND 게이트를 거친 값은 비트 값으로 1010 이며, 16 진수로 0x0A 가 됩니다.
이처럼 & 연산을 하게되면 한 가지 특징이 있습니다.
바로 앞에 나온 변수의 비트값이 0 이면 다음에 오는 값의 비트가 무엇이든 무조건 0 이 되며,
앞 변수의 비트값이 1 일때 다음 변수의 비트값에 따라 그 값이 결정되게 된다는 것 입니다.
따라서 이런 연산은 이미지처리에서 필터링으로도 활용 될 수 있습니다.
다음은 && 연산에 대해 알아보겠습니다.
앞서 말했듯이 && 는 논리 연산자 입니다.
주어진 두개의 변수의 논리값의 AND 연산인 것 입니다.
이해를 돕기위해 소스코드를 먼저 보겠습니다.
#include <stdio.h>
int main(void)
{
int a, b, c;
a = 0x0A;
b = 0x0E;
c = 0;
c = a&&b;
printf("c = %d[0x%x]\n",c,c);
return 0;
}
앞선 & 예제의 코드에서 c=a&b 를 c = a&&b 로만 바꿨습니다.
결과는 아래와 같습니다.
c = 1[0x1]
값이 1 이 나왔습니다.
계산된 값 (0x0A) 가 아닌 논리값 1 이 나온 것입니다.
이것이 실제로 어떤 로직을 거쳤는지 그림으로 살펴 보겠습니다.
이처럼, 값 자체를 계산하지 않고, 각 값의 논리 값을 연산하여 그 결과 또한 논리 값으로 표현한 것 입니다.
만약 변수 A 또는 B 의 값이 0 이면 False 가 나올 것입니다.
논리 값은 0이 아닌 모든 숫자가 1(True) 임을 알아야 합니다.)
즉 -1 도 True 입니다.
간혹 0보다 작은 숫자를 False 로 착각 하는 경우가 있는데요. 0 이 아니면 True 입니다.
따라서
-1 & 1 = 1 이라는 것을 유념 하시기 바랍니다.
| 와 || (or ) 는 설명하지 않겠습니다.
단지 AND 연산이 OR 연산으로 바뀐것일 뿐 원리는 같습니다.
'코딩을 합시다 > 최대한 쉽게 설명한 C 언어' 카테고리의 다른 글
초등학생도 이해하는 C 언어 - 비트연산자 (0) | 2020.05.22 |
---|---|
초등학생도 이해하는 C 언어 - 조건 연산자 (삼항 연산자) (0) | 2020.05.07 |
초등학생도 이해하는 C 언어 - 논리 연산자 (0) | 2020.05.07 |
초등학생도 이해하는 C 언어 - 관계 연산자 (0) | 2020.05.07 |
초등학생도 이해하는 C 언어 - 증감 연산자 (0) | 2020.05.07 |
댓글