C 프로그래머가 알아야할 것들 - Chapter 3. 운영체제와 컴퓨터 원리

김성훈 (sunghun84@nate.com)

Chapter 3. 운영체제와 컴퓨터 원리

(1) 운영체제란?
(2) 이벤트
(3) 프로세스와 쓰레드
(4) 컴퓨터는 계산기다
(5) 디지털과 아날로그
(6) 2D게임이 3D게임보다 빠르다?

(1) 운영체제란?

초기에 컴퓨터는 컴퓨터를 키자마자 애플리케이션 디스크를 삽입해야만 했습니다.
그리고 특별한 경우를 제외하고는 다른 프로그램 사용시에는 재부팅 시켜야만 했습니다.
이 방법은 매우 불편했습니다. (비디오 게임기들은 아직 이 방식을 채용하고 있는 경우도 있습니다.)

그래서 유닉스, MS-DOS등의 운영체제가 나오게 됐습니다. (많은 분들이 오해하시는 것이 있으신데, MDIR은 운영체제가 아닙니다. 인터페이스를 제공해주는 프로그램이죠)
각 운영체제하에 프로그램을 구동시킨후, 프로그램 종료시에는 그 운영체제로 돌아오게끔 하는 방식을 취한것이죠.

또한 프로그래머를 위한 장치 지원 인터페이스를 제공해 주기도 했습니다. (MS-DOS에서는 매우 미약했지만, 윈도우로 넘어와서는 극찬 받는 기능이죠)
이전에는 그래픽 카드나 프린터, 사운드 카드마다 출력을 지원해주는 방식이 달랐습니다. 점 하나 찍거나 소리를 내는방법이 하드웨어에 따라 달랐던것이지요.

그래서 각 하드웨어 장치(여기선 일반적으로 그래픽 카드와 사운드 카드를 의미합니다)를 컨트롤 하기 위한 작업들은 프로그램 개발 업체마다 따로 이루어져야했고, 그렇기에 발매된지 얼마 되지 않은 하드웨어나, 판매량이 적은 비 인기 하드웨어의 경우는 지원되지 않는 경우가 대부분이었습니다.

상황이 이렇다보니 프로그래머들은 프로그래머 나름대로 다수의 하드웨어 장치를 지원하려다 보니 힘들었고, 사용자들은 사용자 나름대로 내 하드웨어가 내가 사려는 소프트웨어의 지원이 되는지 곰곰히 따져봐야하는 불편한 상황이었죠.

물론 DOS시절에도 VESA (Video Electronics Standard Association)등에서 그래픽 카드의 표준화를 시키긴했지만, 호환성 문제는 고질적인 문제였습니다.

그래서 나온 것이 바로 윈도우입니다.

대게 MS-DOS와 비교되는 윈도우의 장점으로 GUI (Graphic User Interface)를 꼽지만, 플러그 앤 플레이나, API (Application Programming Interface)도 빠지면 안될정도로 중요한 요소입니다.

플러그 인 플레이는 자동 하드웨어 장치 인식 기능으로, MS-DOS의 단점을 보완해주기에 충분했습니다.

API는 프로그램 개발용 함수 모음으로, 점찍기, 타이머, 텍스트 출력, 마우스 입력, 키보드 입력 등등 프로그램 개발에 필요한 기본적인 기능을 지원해준 것입니다. 각 프로그램마다 자체적으로 지원하기 위해 엄청난 시간투자를 해왔던 작업들을 운영체제가 지원해줌으로써, 프로그램 개발이 한결 편해진것입니다.

여기서는 주로 윈도우의 예를 들겠지만, 다른 운영체제도 용어만 틀리지 원리는 비슷하니 이해하시는데 무리는 없을겁니다.

(2) 이벤트

MS 윈도우(이하 윈도우)에서 이벤트란 윈도우에서 발생하는 정보들을 말합니다.
즉, 마우스 이동, 마우스왼쪽 버튼 클릭, 마우스오른쪽 버튼 클릭, 키보드 누름, 키보드 뗌, 문자 키 누름,프로그램 시작, 프로그램 종료등 다양한 상황마다 이벤트가 발생하는데, 그렇게 발생되는 이벤트를 메시지로 프로그램에 보내주는 것입니다.

그 메시지를 받아서 필요한 메시지를 이용하여 처리해주는 것이 윈도우 프로그래밍에서의 이벤트 프로그래밍 방식이라고 합니다.

하드웨어 장치를 어느 회사 제품이냐, 어떠한 식으로 제어해야 하는가를 프로그래머가 신경써야한다면, 운영체제가 이벤트를 보낼수 없겠죠? 하드웨어 제어를 프로그래머가 만든 응용 프로그램이 한다면, 운영체제가 그 하드웨어에서 발생한 이벤트를 보낼 수 없을겁니다. (응용 프로그램 내부에서 그 하드웨어를 제어하며 이벤트 발생시 메시지를 보낼 수는 있겠지만요.)

하드웨어의 접근을 운영체제가 직접 관리하기 때문에, 프로그래머들은 그 부분에 신경않아도 되고, 이벤트 발생시 그 이벤트를 메시지로 받아서 처리하기만 하면 되는것이죠

(3) 프로세스와 스레드

간단히 말해서 프로그램이 실행되고 있는 것을 프로세스라 합니다.
이런 프로세스를 (어느정도는 의미가 다르지만) 태스크라 부르기도 하죠.
우리가 흔히 들어온 멀티 태스크란, 다중 프로그램 구동이라고 생각해도 될겁니다.
이 멀티 태스크를 통해 우리는 동시에 프로그램이 실행되고 있구나라고 생각하시는 분도 많을겁니다.
그러나 실상은 눈깜짝할사이에 여러개의 프로그램이 번갈아가면서 실행되고 있기에 우리는 동시에 작동하는걸로 생각되는것이죠.

스레드는 프로세스 내부의 실행 단위를 말합니다. 프로세스내에서 스레드가 여러개 존재하여 처리되는 것을 멀티 스레드라 하는것이죠.
예를 들면 메신져에서 음악 재생하면서 채팅(메시지 입력)을 할 수 있는 것은, 음악 재생과 채팅기능이 스레드 단위로 구동되기 떄문입니다.
만약 이 프로그램이 태스크 단위로 구동되었다면, 그 프로그램을 이용하여 음악을 재생하는중에는 그 프로그램을 이용한 채팅이 불가능하게 됩니다. 음악이 자동으로 멈추거나, 중지 시키지 않는다면 말이죠.

(4) 컴퓨터는 계산기다

컴퓨터는 계산기라고 한다면, 아니? 계산기에서 동영상도 볼 수 있고, 3D게임도 할 수 있고, 그림도 볼 수 있고, 음악도 나온다는 게 말이되냐고 하시는분도있으실겁니다.
하지만 사실입니다. 입력장치(키보드,마우스)나 출력장치(모니터,프린터,스피커)는 주변기기입니다. 컴퓨터는 입력장치로부터 신호를 받아 그 것을 비트로 변환하여 프로그램(혹은 운영체제)에 전달한후 그에 맞는 처리를 하다가, 출력 장치로 출력해줄 필요가 있을 때 출력장치에 신호를 보내서 출력해주게 됩니다. 이 과정들도 비트로 이루어져있습니다. 컴퓨터는 이진수(on, off)밖에 모르기 때문입니다.

초기 컴퓨터(최초의 컴퓨터로는 애니악으로 잘못 알려져있는데 실은 앨런 튜닝이 세계 2차대전에서 독일군 암호 해독을 위해 만들어진 콜로서스입니다)는 연산속도도 느리고, 연산을 위한 저장 장소(덧셈을 해주려면, 최소 두 개의 저장 장소가 필요합니다. 첫 번째값, 그리고 더해줄 두 번째값. 세 번째 값은 결과값이 필요하다고 생각하실지도 모르겠습니다만, 첫 번째 값과 두 번째 값은 연산후에는 필요가 없어지기에 둘중 아무곳에나 결과값을 저장하면 됩니다.)가 작았기 때문에 간단한 처리밖에 못했습니다. 그런 계산들을 하기 위해 컴퓨터가 만들어졌고, 그것이 당연했죠.

그러나, CPU와 RAM의 속도와 용량이 증가함에 따라서, 컴퓨터의 연산속도가 급격히 상승했습니다. 그에 맞춰 소프트웨어와 입출력 장치들도 발전을 거듭하면서, 비트 단위로 이루어진 데이터를 이용하여 동영상을 재생하고, 그림 파일을 보여주고, 3D게임도 가능하게 된 것입니다. 동영상 파일이나, 그림 파일등이 비트를 기반으로 한 정보로 이루어졌었다고 배웠죠? 그런 데이터들을 출력하는 과정도, 출력 장치 혹은 주변 기기(그래픽 카드나 사운드 카드)의 도움을 받기는 하지만, 일반적으로 컴퓨터의 연산기능을 이용합니다.

그렇기에 컴퓨터는 매우 빠른(이런 말로 표현하기엔 터무니없이 부족하지만) 계산기라고도 할 수 있는것입니다.

(5) 디지털과 아날로그

컴퓨터를 이해하기 위해서 우리는 디지털과 아날로그에 대해 이해할 필요가 있습니다. 왜냐하면 컴퓨터는 수치를 기반으로 한 디지털에 기초하고 있기 때문입니다. (그렇기 떄문에 수학과도 큰 연관이 있습니다.)

아날로그란 연속된 정보를 말합니다. 물론 아날로그도 수치로 표현할 수 있지만, 좀 더 세분화된 정보를 다룬다는 것이 차이점입니다.

그에 반해 디지털은 단절된 정보를 다룹니다. 바로 중간값을 취하지 않는다는 얘기입니다. 예를 들면, 컴퓨터에서 작동하는 시계를 직접 만든다고 생각해봅시다. 이 시계는 큰 기능이 필요 없기 때문에 초까지만 다룬고 한다면, 0.1초나, 0.01초등의 정보를 다루지 않게 됩니다. 물론 0.01초까지 다룬기로 했다면, 이야기가 또 틀려지지만요. 결과적으로 중간값을 다루지 않죠.

컴퓨터는 디지털로 이루어져있지만, 아날로그 데이터도 다룰 수 있기 때문에 이 두 방식의 차이점을 기억해두도록 합시다.

(6) 2D게임이 3D게임보다 빠르다?

우리가 흔히 하는 착각은 2D게임이 3D게임보다 빠르다. 혹은 2D게임은 저 사양이다라는 생각입니다.

이것은 지금까지 배운 논리를 적용하면 쉽게 알 수 있는 것인데, 컴퓨터에서 구동되는 모든 과정은 계산에 의한것입니다.

그렇기 때문에, 2D던, 3D던 게임의 속도는 얼마만큼 많은 계산을 필요로 하는지에 달려있는 것이지, 같은 (혹은 비슷한) 기능을 가진 게임이라면 2D와 3D의 기본적인 연산 속도의 차이(3D는 일반적으로 폴리곤=다각형으로 이루어져 있기에 기본적으로 이루어져야할 연산이 많고, 실수 연산이 많이 필요하기 때문에 더욱 2D보다는 확실히 연산할 것이 많습니다.)는 있을 수 있어도, 게임의 규모가 커지다보면 오히려 2D게임이 느려지는 경우가 발생하게 됩니다.

3D게임의 경우는 모션에 따른 변화되는 정보를 가지고 원본 데이터에서 변화시키는 방식인데 반해, 2D의 경우는 캐릭터의 모든 행동 정보를 이미지 파일로 가지고 있어야하기 때문이다.

그리고, 시각적 효과가 거의 없는 게임인 FM시리즈(Football Manager의 약자로, 원래는 Championship Manager 시리즈였던 게임)의 경우 왠만한 3D게임보다도 속도가 느린데, 이 것은 이 게임이 처리해야 될 데이터가 많기 때문입니다. 모든 경기 결과는 랜덤이 아닌, FM시리즈의 규칙(데이터에 기반하되, 그 데이터가 전부가 아닌)에 따른 결과가 나와야 하기 때문에, 모든 경기 결과를 계산해야되는데, 그 계산해야 될 데이터가, 왠만한 3D게임보다 많기 때문에 느린 것입니다.

어때요? 컴퓨터의 속도에 대한 감이 오시나요?
C 프로그래머가 알아야할 것들 - Chapter 2. 비트의 법칙

김성훈 (sunghun84@nate.com)

Chapter 2. 비트의 법칙

(1) 비트가 뭐지?

(2) 프로그램 작성하는데 비트가 왜 필요한걸까?

(3) 데이터형

(4) 바이트로 구성된 파일

(5) 비트 연산자

(6) 간단히 구현해보는 압축


(1) 비트가 뭐지?

비트란 Binary Digit. 즉 이진수의 약자입니다. 한마디로 이진수를 의미한다고 할 수 있죠. 비트는 컴퓨터에서 제어 가능한 데이터의 최소단위입니다. 하지만, 컴퓨터에서 입출력할때 사용하는 최소 단위는 바이트죠. 둘다 최소단위인데...저게 뭔소린가...하실분도 있을겁니다.

간단히 설명하자면, 비트란 저번 강좌에서 배웠던 이진수 10을 2비트(2진수 2자리 수이기에)로 표현 가능하고 제어 가능하단 의미고, 바이트는 비트 8개가 모여서 구성된 것이 1바이트로, 파일이나 데이터형의 최소단위로 쓰입니다.

(2) 프로그램 작성하는데 비트가 왜 필요한걸까?

많은 분들이 프로그램을 만드는데 왜 비트가 필요한지 의문을 가지실거라고 생각합니다.
그런데, 위에서 설명했듯이 데이터의 최소단위는 비트입니다.

최적화 된 프로그램이란 메모리와 속도 모두 만족 시키는 프로그램을 말하는데, 그것을 만족하기 위해선 비트 단위 연산 또는 처리가 필수이기 때문입니다.

하드웨어의 발전에 따라 빠른 속도보다는 쉬운 사용법과, 유지 보수 또는 코드 재사용이 쉬운 프로그램이 인기를 끌고 있는건 사실입니다.

하드웨어가 발전함에 따라 그 하드웨어의 기능을 활용하기 위한 기술이 적용되다보니 여전히 빠른 프로그램을 작성할 필요성은 존재합니다.
메모리와 비트 단위 연산 권한이라는 강력한 기능을 부여받은 이상 비트에 대해 알아두는 것은 당연하다고 할 수 있습니다.

(3) 데이터형

C언어에서는 다양한 데이터형을 제공합니다.
여기서는 주로 사용되는 몇 개의 데이터형만 가지고, 비트와 관련해 알아보도록 하죠.

흔히 문자형으로 알려진 char (캐릭터형)는 1바이트로 이루어져있습니다.
일반적으로 1바이트=8비트이므로, 0000 0000 이렇게 8자리 2진수만큼 사용할 수 있는데, 2의 7승은 256 (첫 자리가 2의 0승이므로, 8비트의 경우 2의 7승만큼 사용 가능합니다.)
이므로, 부호가 없는 경우는 0~255, 부호가 있는 경우는 -128~127(C표준에서는 -127까지 보장해준다)까지 사용 가능하게 되는겁니다. 부호가 있는 경우는 최상위 비트를 부호 비트로 사용하게 되므로 사용 가능한 수의 범위가 반으로 줄 게 됩니다.

2바이트 데이터형인 short int 도, 2의 15승인 65536만큼의 수를 사용할 수 있는데, 부호 없는 경우 0~65535, 부호가 있는 경우 -32768~32767까지의 수를 사용할 수 있는거죠. 32비트 데이터형도 마찬가지로 2의 31승만큼 사용 가능하다고 알고 계시면 됩니다.

데이터형에 따른 사용범위는 곧 대중화될 예정으로 알려져있는 64비트 운영체제에서 주로 사용될 64비트 데이터형도 마찬가지겠구요.

(4) 바이트로 구성된 파일

비트 8개가 모여서 만든 바이트가 모여서 만들어진 것이 파일입니다.
우리가 흔히 사용하는 이미지 파일들도 알고보면 색상 정보를 담고 있는 바이트의 집합입니다. 여기서 조금 부연 설명을 하자면, BMP(비트맵)파일의 경우는 헤더나 컬러 테이블 정보도 담고 있긴하지만, 일반적으로는 RGB색상값만 가지고 있다고 보시면 됩니다. RGB 색상 값은 Red 1바이트, Green 1바이트, Blue 1바이트씩 저장됩니다.

색상값을 가지고 있다가 프로그램에서 BMP파일을 읽어들였을 때, 색상 정보를 읽어서 RGB색상값을 조합한후 점을 찍어서 (BitBlt함수로도 찍을 수 있는데라고 생각하실분도 있으시겠지만, 그 함수도 결국 내부적으론 점을 찍어서 표현해줍니다.) 그 색상을 모니터에 표현하도록 명령을 내려주기 때문에, 우리 눈에는 컬러 이미지를 볼 수 있는겁니다.

저장되어 있는 RGB색상값을 아무런 압축도 하지 않고 모두 가지고 있는 경우가 위에서 설명한 BMP파일 포맷이고, JPG의 경우는 고도의 압축 기법(압축률도 지정가능합니다)을 통해서 용량을 줄였지만 결과적으로는 색상값을 가지고 있다 신장(압축해제)후 화면에 뿌려주는 원리는 비슷합니다.

벡터 그래픽 파일의 경우에는 점,선,곡선등의 정보를 저장하고 있는 포맷이지요. 그래서 화면에 축소나 확대에서도 같은 이미지를 볼 수 있는것이지요.

동영상 파일도 많은 양의 그림 정보를 담고 있다가, 1초에 몇번 이상(1초에 몇 번 화면이 갱신되는지를 프레임이라고 하는데, 초당 24내지 30프레임은 되어야 깜빡임이 사람 눈에 보이지 않는다고 합니다. 일반적으로 모니터의 경우는 60번 이상 갱신되고 있죠)갱신되는지에 따라 그것을 재생시켜줍니다.

음악파일도 마찬가지로, 소리 정보를 디지털값(수치값)으로 가지고 있다가, 그 정보를 재생시간에 맞춰 재생하는 방식을 취하고 있죠.

스타크래프트 리플레이 파일의 경우에도 비슷하게 첫 위치값을 저장한후에 거기서 변화한 값과 내린 명령,시간값들을 저장했다가, 리플레이 메뉴에서 재생시 그 정보를 바탕으로 게임을 재생시키는 것이지요. 그래서 리플레이 파일의 용량이 그다지 크지 않은것입니다.

게임 세이브 파일의 경우에도, 그 캐릭터의 레벨, 무기 일람, 체력, 공격력, 방어력 등의 파라미터와, 그 캐릭터의 현재 위치, 플레이 시간 등의 정보를 저장하고 있습니다. 물론 에디트가 힘들 게 하기 위해 단순한 파일 구조(순차적)으로 구성하지 않는 경우가 대부분이긴하지만요.

모든 데이터는 바이트 단위로 저장된다는 것. 그 바이트를 구성하고 있는 것은 비트라는 것 이것이 핵심입니다.

(5) 비트 연산자

자 비트에 대해 배웠으니 비트 연산을 한번 해봐야겠죠?
비트연산은 부울대수를 배우셨던 분들은 매우 친숙하실겁니다.

비트연산에 사용되는 비트연산자란 논리 곱 (&) , 논리 합 (|), 논리 부정 (~), 베타적 논리합(^)이 있습니다.
여기서 시프트 연산자 좌측 시프트 (<<) 우측 시프트 (>>)도 있죠.

논리곱은 둘다 1일 때만 참(1)이 됩니다.

1 & 1 = 1
1 & 0 = 0
0 & 1 = 0
0 & 0 = 0

논리합은 둘중에 하나라도 1이면 참(1)이 됩니다.

1 | 1 = 1
1 | 0 = 1
0 | 1 = 1
0 | 0 = 0

베타적 논리합은 두수의 값이 달라야만 참(1)이 됩니다.

1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1
0 ^ 0 = 0

논리 부정은 0은 1로, 1은 0으로 만들어줍니다.

~1 = 0
~0 = 1

이 되는 것이죠.


좌측 시프트 연산자는 비트를 왼쪽으로 옮겨주고, 빈자리엔 0을 넣어줍니다.

0011 0010 << 2

이 연산후에 0011 0010 (10진수 50)에서 1100 1000 (10진수 200) 로 바뀝니다.
왼쪽으로 2번 이동했더니 수가 4배가 되었죠?
잘 보시면 시프트 연산자 한번당 수가 2배가 된다는 것을 아실수 있을겁니다.


우측 시프트 연산자는 비트를 오른쪽으로 옮겨주고, 빈자리엔 0을 넣어줍니다.

0011 0011 >> 2

이 연산후에는 0011 0010 (10진수 50)에서 0000 1100 (10진수 12) 가 되었습니다.
좌측 시프트 연산자와 마찬가지로, 우측으로 2번 이동했더니 수가 4분의 1이 되었죠? (12.5여야하지만, 소수점 이하는 버립니다)


(6) 간단히 구현해보는 압축

압축방법에는 런 렝스 코드, 허프만 코드등 다양한 방법이 있는데요, 여기서는 시프트 연산자와 비트 연산자의 조합으로 간단한 압축을 구현해보겠습니다.

아까 데이터를 압축하려면 현재 데이터에서 변화한 정보를 담는 것이 좋다고 했었죠?

그 원리를 이용하는 것입니다.

주로 다른 파일보다는 이미지, 음악 파일, 동영상 파일등에 사용되는 데이터 압축의 원리는 이 바이트를 기본으로 한 데이터들이 비트로 이루어져있다는 것이 핵심입니다.

어떤 데이터든 현재 상태와 다음상태의 값을 모두 가지고 있는 것보다 현재값 (초기값 또는 현재값은 모든 데이터를 기록해둬야 합니다)을 기록해둔후 차후에 변화되는 값을 저장하게 되면 적은 용량으로 데이터를 기록할 수 있을겁니다. 일반적으로 한 픽셀값은 1바이트로 저장된다고 얘기했었죠? 그런데 방금전 픽셀값은 10이고 다음 좌표값은 30이면 20만 저장하는 것입니다. 그렇게 되면 6비트 (2의 5승이 32이니, 0~31까지 사용가능)내에 데이터를 담을 수 있습니다. 그리고 나서 좌측 시프트 시키면 하위 2비트에 0이 들어오겠죠? 그 2비트에 다른 정보를 담게 되면 전체적으로 용량이 줄 게 됩니다. 이것이 바로 데이터 압축의 원리죠.
펌 ) Devpia VC++ 강좌 엘키(sunghun84)
C 프로그래머가 알아야할 것들 - Chapter 1. 진법

김성훈 (sunghun84@nate.com)

Chapter 1. 진법

(1) 왜 진법에 대하여 배워야 하는가?
(2) 2진법
(3) 8진법
(4) 16진법

(1) 왜 진법에 대하여 배워야하는가?

진법이 뭘까요? 바로 수를 세는 단위입니다.

진법중에는 우리가 흔히 사용하고 있는것은 60진법(초,분을 재는데에 쓰이는 방식. 0~59까지 세고, 60이 되었을떄 자리올림하는 수체계)이나, 10진법(0~9까지 세고, 10이 되었을 때는 자리올림을 하는 우리가 기본적으로 수를 세는방식)등도 있습니다.

그 중에서도 여기서 배울 것은 2진법,8진법,16진법이 있는데요, 이 진법들에 공통점은, 모두다 2진수와 연관이 있는 진법이라는 겁니다.

왜 2진수(혹은 2진수와 관련이 깊은 진법에 대해 알아야 될까요? 그 이유는 컴퓨터는 0과 1밖에 구분하지 못하기 때문입니다. 컴퓨터는 전류가 흐를 때, 흐르지 않을때를 통해 구분하는것으로써, 2진수와 일맥 상통하게 됩니다. 2진수는 또한 참과, 거짓으로 상태를 표기하는 부울대수와도 연관이 깊죠.

그런데 게임과, 메신져 이런것들이 0과 1만으로 실행 되는거라고? 거짓말 아냐? 라고 생각하실분들도 계실텐데요, 그것에 대해서는 2번째 챕터 비트의 법칙에서 자세히 설명하도록하겠습니다.

16진수는 2진수 매우 연관이 깊어 2진수를 4개 단위로 읽을 때 유용하게 이용되기도 합니다. 8진수는 16진수와 비슷하게 2진수를 3개 단위로 읽을 때 혹은, 10진수에서의 상호 변환등에서 자주 사용되게 됩니다.

또한, 컴퓨터는 수를 계산(연산)을 하는 기계입니다. 그렇기 때문에, 수를 표현하는 방식(그 중에서도 컴퓨터가 사용하는 2진수와 관련이 깊은)에 대해서 알아둬야할 필요가 있는 것입니다.

(2) 2진법

아까 언급했듯이, 컴퓨터는 0과 1밖에 수를 인식하지 못합니다.

2진수는 0과 1로써 수를 세는 방법입니다.

자리수가 2가 되었을때 자리 올림을 하여 10으로 표시하는 수체계죠.

2진수는 표현할 때

0011 (2)

위와같이 표현하곤합니다. 괄호는 반드시 써야하는건 아니고, 혼돈의 여지가 있을 때만 사용하곤합니다.

2진수
10진수

0000
0

0001
1

0010
2

0011
3

0100
4

0101
5

0110
6

0111
7

1000
8

1001
9

1010
10


위의 표를 보시면, 대강 어떤지 감이 오실겁니다.
10진수가 11일때 2진수로는 몇이 될까요?
네 그렇죠~ 1011이 되는겁니다.


그런데...2진수가 너무 읽기 힘들다구요?

8 4 2 1
1 0 0 1 (자릿수가 1일 때마다, 머리위에 위치한 수만큼 더해줍니다)



8에 위치한 2진수가 1이니 8, 4와 2자리에 위치한 수는 0이니 그냥 내버려두고, 1의 자리에 위치한 수가 1이니 1. 그래서 나온수인 8과 1을 더하면 9가 되는거죠. 쉽죠?

마찬가지로 이진수가 커질때에도

128 64 32 16 8 4 2 1
0 0 0 0 0 0 0 0

이런식으로, 수가 하나 증가할때마다 수가 배로 증가하게 됩니다. 이렇게 하니 2진수 읽는 법은 감이 오죠?


그런데...음수를 표현할땐 어떻게 해야 할까요?

-0011 이런식으론 안되냐구요?

아쉽게도, 10진수와는 달리 -부호를 사용할수 없습니다.

그래서 최상위 비트(가장 앞에 있는 수를 최상위 비트=MSB라 부르게 되죠. 비트란 다음 강좌에서 배우게 될 바이너리 디지트=이진수의 약자입니다)를 부호 비트로 사용하게 되는것이죠.

최상위 비트가 0이면 양수, 1이면 음수로 표현 하기로 했습니다.

0001은 1, 1001은 -1 이렇게 말이죠.


그런데 이것은 문제가 있습니다.

2진수의 계산이 힘들어진것이죠.

1001 + 0001 = 1010

(-1) (1) (0 이어야 함)



2진수의 덧셈에서 자리 올림수가 발생하면 일반 덧셈에서 자리 올림수와 마찬가지로 처리해주면 됩니다.

그건 그렇고, 뭔가 이상하죠? 1010이라니...최상위 비트가 1이니 음수인거 같고, 뒤가 010이니 -2인거 같은데... 어? 0이 아니네요?

그래서 나온 것이 1의 보수입니다.


1의 보수란, 음수 표현시에 0을 1로, 1을 영으로 모든 수를 반전 시키는것이죠.

1의 보수로 표현하자면,

0001은 1, 1110은 -1이 되는거죠.


자..아까 계산이 잘못되었던 -1에서 1을 더해볼까요?

1110 + 0001 = 1111

(-1) (1) (0이어야 함)

어? 여전히 뭔가 이상하죠?? 최상위 비트가 1이니 음수 인거 같고....111이라면 -7? 왜 또 0이 아니지? 또 문제가 있었습니다.


그래서 2의 보수란 것이 나오게 된것입니다.

2의 보수란 0을 1로, 1을 0으로 모두 바꿔준후에 1을 더하는 방법입니다.

0001은 1, 1111은 -1이되는것이죠.



그럼 다시...계속 잘못되었던계산인 -7에서 7을 더해봅시다.

1111 + 0001 = 10000

(-1) (1) (0이어야 함)

음...이번에도 최상위 비트가 1이군요. 그럼 음순가? 그런데 뒤가 0000이네요? 하지만 이 계산은 맞습니다. 맨앞에 초과된 1은 무시하기 때문입니다. 그래서 0000 즉 0이 되는것이죠.



왜 2의 보수가 사용되는지 아셨겠죠?

참고로 1의 보수의 또다른 문제점은 0이 두 개이기 때문입니다.

1111 1111과, 0000 0000 각각 음수 0 양수 0을 의미합니다.

이에 비해 2의 보수는 0000 0000은 당연히 0이고, 0의 1의 보수인 1111 1111에서 1을 더하면 1 0000 0000이 되고, 이때 초과된 1은 무시하게 되므로 0은 양수 0 하나만 남게 되는것이죠. 이로써 아까 -1에서 1을 더하는 계산에서의 초과된 1을 무시하는 이유도 함께 이해가 되시죠?



(3) 8진법

8진법이란 0~7로 수를 세는 방법입니다.

8진수는 자릿수가 7이 넘어 8이 되었을때는 자리 올림하여서, 10으로 표현하는 수체계입니다.

8진수를 표기할때

12 (8)

이런식으로 작은 괄호로 8을 붙여서 표현하곤 합니다. 2진수와 마찬가지로 꼭 표기해줄 필요는 없습니다.
C언어등의 고급 언어에서 사용시에는 0(숫자 0)을 붙여서 사용하죠.

아래 표를 보시면, 2진수, 8진수, 10진수의 관계를 아실수 있을겁니다.

2진수
8진수
10진수

0000
0
0

0001
1
1

0010
2
2

0011
3
3

0100
4
4

0101
5
5

0110
6
6

0111
7
7

1000
10
8

1001
11
9

1010
12
10




8진수는 그 자체적인 의미도 중요하지만, 2진수에서의 변환이 매우 편리하다는 장점이 있습니다.

바로 수를 세 개단위로 묶어서 표현하면 되는것이죠.



4 2 1
1 1 1 (7입니다)

8진수로 바꿀때는, 4+2+1=7이 되는거죠.



이런식으로

4 2 1 4 2 1
1 1 0 0 1 1

4+2=6 2+1=3

8진수로 63이 되는겁니다.


10진수 524을 8진수로 구해봅시다.

524 / 8 = 65 나머지 4

65 / 8 = 8 나머지 1

8 / 8 = 1 나머지 0

1 / 8 = 0 나머지 1

1014(8)

즉, 나머지를 역순으로 나열하면, 10진수에서, 8진수를 구할 수 있습니다.



다시 8진수 1014를 10진수로 바꿔봅시다.

1014(8) = 4 x 8에 0승 + 1 x 8에 1승 + 1 x 8에 3승
= 4 x 1 + 1 x 8 + 1 x 512
= 4 + 8 + 512
= 524

524(10)

각 자리수에 맞춰서 곱해주면, 8진수에서 10진수로 변환되는겁니다.


(4) 16진법

16진법이란, 수를 0부터 15로 세다가, 16이 되어 자리올림할땐 10으로 표현하는 방법을 말합니다.

그런데...뭔가 조금 이상하죠? 0~15로 수를 센다면, 0~9는 괜찮겠지만, 10부터 15는 자리 올림된 10~15와 같게 되니까요.

그래서 10~15는 A~F로 표현하게 됩니다.

16진수도 8진수 2진수와 마찬가지로,

AF (16)

위와 같이 표기할 수 있습니다.

C언어등 고급언어에서 16진수 표현시 숫자 앞에 0x (숫자 0과 알파벳 x)를 붙여서 사용합니다.


아래 표를 보시면 진법에 따른 수 표현 방식을 이해하실수 있을겁니다.

2진수
8진수
16진수
10진수

0000
0
0
0

0001
1
1
1

0010
2
2
2

0011
3
3
3

0100
4
4
4

0101
5
5
5

0110
6
6
6

0111
7
7
7

1000
10
8
8

1001
11
9
9

1010
12
A
10

1011
13
B
11

1100
14
C
12

1101
15
D
13

1110
16
E
14

1111
17
F
15


16진수도 8진수처럼 2진수에서의 변환이 쉽다고 했었죠?

16진수도 2진수를 8진수로 변환하는 것과 비슷합니다. 2진수 4개씩 묶어서 16진수로 변환하면 되는것이죠.

8 4 2 1
1 1 0 0 (12입니다)

8+4=12인데, 12는 알파벳 C로 표현하기로 했으니,

8+4=C로 표현할수 있는것이죠.

8 4 2 1 8 4 2 1
1 0 1 0 0 0 1 1

8+2=A 2+1=3

A3으로 4자리씩 묶어서 변환함으로써 2진수를 좀 더 읽기 쉽게 하는것이죠.

16진수는 또한 니블(Nibble)에 기본 단위가 됩니다. 니블이란 비트를 4개씩 묶어서 표현하는 방식으로써, 16진수와 같은 방식으로 표현할 수 있게 되죠.

이것으로 각 진법에 대하여 알아봤는데요, 2진수, 8진수, 16진수가 모두 연관이 있다는 것을 알수 있었습니다. 특히나 2진수는 어떤수로나 변환이 쉽다는 것도 말이죠.

+ Recent posts