핵심 키워드 : 문제 해결
, 성능/용량/비용
우리 자신에게 동기부여를 해 봅시다.
컴퓨터 구조를 이해하고 있다면 문제 상황을 더 빠르게 진단할 수 있고, 문제 해결
의 실마리를 다양하게 찾을 수 있습니다.
컴퓨터란 써놓은 코드를 돌리는 계산기가 아니라 분석의 대상이 될 수 있으니까요!
즉, 다양한 문제를 스스로 해결할 줄 아는 개발자로!
우리가 개발한 프로그램이 어떤 환경에서 어떻게 작동하는지 우리는 알고 있어야 하고, 프로그램을 위한 최적의 컴퓨터 환경을 스스로 판단할 수 있어야 합니다.
그 과정에서 우리는 성능, 용량, 비용
의 타협점을 합리적으로 조율할 수 있는 개발자가 되어 갑니다.
핵심 키워드 : 데이터
, 명령어
, 메모리
, CPU
, 보조기억장치
, 입출력장치
, 시스템 버스
데이터
: 컴퓨터가 이해하는 정적인 정보
명령어
: 데이터를 움직이고 컴퓨터를 작동시키는 정보
CPU
메모리
(RAM)보조기억장치
입출력장치
★메모리 - 아래 3가지 기억하세요★
★CPU - 아래 3가지 기억하세요★
보조기억장치
입출력장치
메인보드와 시스템 버스
메인보드에 연결된 부품들은 서로 정보를 주고 받을 수 있는데, 이 중 컴퓨터의 네 가지 핵심 부품을 연결하는 가장 중요한 버스는 시스템 버스
입니다.
시스템 버스는 위와 같이 구성되어 있습니다.
기본 미션 1)
핵심 키워드: 비트
, 바이트
, 이진법
, 2의 보수
, 십육진법
비트: 0과 1을 나타내는 가장 작은 정보 단위
바이트: 여덟 개의 비트를 묶은 단위
이를 1000개씩 묶어서 킬로바이트, 메가바이트, 기가바이트, 테라바이트 …로 단위가 커집니다.
그 외, 워드 (word)란 CPU가 한 번에 처리할 수 있는 데이터 크기를 의미합니다.
워드 크기는 CPU마다 다르지만, 현대 컴퓨터의 워드 크기는 대부분 32비트 (x86), 64비트 (x64)입니다.
0과 1밖에 모르는 컴퓨터에 어떤 숫자를 알려 주려면 십진수가 아닌 이진수로 알려 주어야 합니다.
이진수의 음수 표현
가장 널리 사용되는 방법은 2의 보수를 구해 이 값을 음수로 간주하는 방법입니다. 이는 간편하게 모든 0과 1을 뒤집고, 거기에 1을 더한 값으로 구할 수 있습니다.
하지만, 이진수만 봐서는 음/양을 구분하기 어렵기 때문에 이를 구분하기 위해 플래그를 사용합니다.
참고) 2의 보수 표현에도 한계는 있습니다. 의 보수를 취하면 자기 자신이 되어 버리기 때문에 본질적으로 해결하기 어렵습니다.
십육진수를 이진수로 변환하기
십육진수 한 글자를 4비트의 이진수로 가주하면 계산하기 쉽습니다.
이진수를 십육진수로 변환하기
이진수 숫자를 네 개씩 끊고, 끊어 준 네 개의 숫자를 하나의 십육진수로 변환한 뒤 그대로 이어 붙이면 됩니다.
기본미션 2)
핵심 키워드: 문자 집합
, 아스키 코드
, EUC-KR
, 유니코드
문자 집합: 컴퓨터가 인식하고 표현할 수 있는 문자의 모음
문자 인코딩: 문자를 0과 1로 변환해야 비로서 컴퓨터가 이해할 수 있습니다.
문자 디코딩: 0과 1로 이루어진 문자 코드를 사람이 이해할 수 있는 문자로 변화하는 과정
오류 검출을 위한 parity bit인 1비트와 문자 표현을 위해 사용되는 7비트를 합하여 8비트를 사용합니다.
완성형 인코딩: 완성된 하나의 한글 글자에 고유한 코드를 부여하는 인코딩 방식
조합형 인코딩: 초성, 중성, 종성에 해당하는 코드를 합하여 하나의 글자 코드를 만드는 인코딩 방식
EUC-KR은 대표적인 완성형 인코딩 방식으로 초성, 중성, 종성이 모두 결합된 한글 낱자에 2바이트 크기의 코드를 부여합니다.
모든 한글을 표현할 수 없는 문제가 있어 CP949로 더욱 다양한 문자를 표현할 수 있게 되었지만, 한글 전체를 표현하기에 넉넉하지는 않습니다.
모든 나라 언어의 문자 집합과 인코딩 방식을 하기 위해 등장하였습니다.
이런 인코딩 방법에는 크게 UTF-8, 16, 32 등이 있습니다.
손으로 계산하기 귀찮아서 만들었습니다.
unicode_input = int(input("0x16진수의 형태로 유니코드를 입력하세요 : "), 16)
if 0x0000 <= unicode_input and unicode_input <= 0x007f:
char = bin(unicode_input)
print('0' + char[2: ])
elif 0x0080 <= unicode_input and unicode_input <= 0x07ff:
char = bin(unicode_input)
first_byte = '110' + char[2 : 2+5]
second_byte = '10' + char[2+5 : ]
print(first_byte, second_byte, sep=' ')
elif 0x0800 <= unicode_input and unicode_input <= 0xffff:
char = bin(unicode_input)
first_byte = '1100' + char[2 : 2+4]
second_byte = '10' + char[2+4 : 2+4+6]
third_byte = '10' + char[2+4+6 : ]
print(first_byte, second_byte, third_byte, sep=' ')
else:
char = bin(unicode_input)
first_byte = '11110' + char[2 : 2+3]
second_byte = '10' + char[2+3 : 2+3+6]
third_byte = '10' + char[2+3+6 : 2+3+6+6]
fourth_byte = '10' + char[2+3+6+6 : ]
print(first_byte, second_byte, third_byte, fourth_byte, sep=' ')
핵심 키워드: 고급 언어
, 저급 언어
, 기계어
, 어셈블리어
, 컴파일 언어
, 인터프리터 언어
사람이 이해하기 쉬운 고급 언어를 컴퓨터가 직접 이해하고 실행할 수 있는 언어인 저급 언어로, 즉 명령어로 변환되어야 합니다.
저급 언어에 크게 두 가지 종류로 0과 1의 명령어 비트로 이루어진 기계어와 이를 조금이나마 읽기 편한 형태로 번역한 언어가 어셈블리어입니다.
컴파일 언어
컴파일러에 의해 소스 코드 전체가 저급 언어로 변환 (컴파일)되어 실행되는 고급 언어입니다.
이렇게 컴파일러를 통해 저급 언어로 변환된 코드를 목적 코드라고 합니다.
인터프리터 언어
소스 코드를 한 줄씩 저급 언어로 변환하여 실행해 주는 도구를 인터프리터라 하며 이에 의해 소스 코드가 한 줄씩 실행되는 고급 언어입니다.
Reference) 모든 프로그래밍 언어를 컴파일 언어와 인터프리터 언어로 칼로 자르듯 구분하기 보다 ‘고급 언어가 저급 언어로 변환되는 대표적인 방법에는 컴파일 방식과 인터프리트 방식이 있다’ 정도로 이해하는 것이 좋습니다.
Further study) 목적 코드가 실행 파일이 되기 위해서는 링킹이라는 작업을 거쳐야 합니다. main.o (main 함수가 들어있는 목적 파일)에 없는 외부 기능 (main의 실행을 위해 필요한 라이브러리 함수)들과 main.o을 연결 짓는 작업이 필요한데 이를 링킹이라고 합니다.
핵심 키워드: 명령어
, 연산 코드
, 오퍼랜드
, 주소 지정 방식
명령어는 연산 코드와 오퍼랜드로 구성되어 있는데, 다른 말로 연산자와 피연산자라고도 부릅니다.
즉, 명령어가 수행할 연산을 연산 코드, 연산에 사용할 데이터 또는 연산에 사용할 데이터가 저장된 위치를 오퍼랜드라고 합니다.
오퍼랜드
오퍼랜드 필드에는 숫자나 문자 등을 나타내는 데이터 또는 메모리나 레지스터 주소가 올 수 있지만, 많은 경우 연산에 사용할 데이터가 저장된 위치, 즉 메모리 주소나 레지스터 이름이 담깁니다. 그래서 이를 주소 필드라 부르기도 합니다.
연산 코드
가장 기본적인 연산 코드 유형은 크게 네 가지로,
로 나눌 수 있습니다.
명령어의 종류와 생김새는 CPU마다 다르기 때문에 연산 코드 또한 CPU마다 다릅니다.
연산의 대상이 되는 데이터가 저장된 위치를 유효 주소 (effective address)라고 합니다. 오퍼랜드 필드에 데이터가 저장된 위치를 명시할 때 연산에 사용할 데이터 위치를 찾는 방법을 주소 지정 방식 (addressing mode)이라고 합니다.
즉시 주소 지정 방식 (immediate addressing mode)
연산에 사용할 데이터를 오퍼랜드 필드에 직접 명시하는 방식입니다.
직접 주소 지정 방식 (direct addressing mode)
오퍼랜드 필드에 유효 주소를 직접적으로 명시하는 방식이지만, 여전히 유효 주소를 표현할 수 있는 범위가 연산 코드의 비트 수만큼 줄어 들어 있는 단점이 있습니다.
간접 주소 지정 방식 (indirect addressing mode)
유효 주소의 주소를 오퍼랜드 필드에 명시합니다. 다만 두 번의 메모리 접근이 필요하여 일반적으로 느린 방식입니다.
레지스터 주소 지정 방식 (register addressing mode)
직접 주소 방식과 비슷하게 연산에 사용할 데이터를 저장한 레지스터를 오퍼랜드 필드에 직접 명시하는 방법입니다.
레지스터 간접 주소 지정 방식 (register indirect addressing mode)
연산에 사용할 데이터를 메모리에 저장하고, 그 주소를 저장한 레지스터를 오퍼랜드 필드에 명시하는 방법입니다.
선택 미션)
Further study) Stack과 Queue
Stack - 나중에 저장한 데이터를 가장 먼저 빼내는 데이터 관리 방식 (후입선출 - last in first out: LIFO)
Queue - 가장 먼저 저장된 데이터부터 빼내는 데이터 관리 방식 (선입선출 - first in first out: FIFO)
스택에 새로운 데이터를 저장하는 명령어가 PUSH, 저장된 데이터를 꺼내는 명령어가 POP으로 가장 나중에 PUSH된 데이터가 가장 먼저 POP되게 됩니다.