CS - #3. 소스 코드, 명령어
우리는 C, C++, Java, Javascript 등 여러 프로그래밍 언어를 사용한다.
하지만 컴퓨터는 0과 1로 이루어진 것들을 이해한다.
그렇다면 우리가 프로그래밍 언어로 작성한 코드를 어떻게 컴퓨터는 이해할 수 있는가?
개발자가 프로그래밍 언어를 통해 작성한 코드를 소스코드라고 한다.
컴퓨터가 이해하는 0과 1은 명령어이다.
이를 기준으로 소스코드에서 명령어로 변환되는 과정을 알아보자.
1. 고급언어, 저급언어
우리가 작성하는 프로그래밍 언어는 대부분 고급언어이다.
고급언어란 사람이 이해하고 작성하기 쉽게 만들어진 언어이다.
반대로 컴퓨터가 이해할 수 있는 언어는 저급언어라고 한다.
저급언어는 기계어와 어셈블리어로 나누어진다.
기계어는 0과 1의 명령어로 이루어진 언어이다.
아무리 컴퓨터가 이해하는 언어라고 해도 위 사진과 같은 기계어를 본다면 이해가 되지 않는다.
이를 조금 보완한 것이 어셈블리어이다.
어셈블리어도 이해하긴 어렵지만 그나마 기계어보다 친숙한 알파벳들로 이루어져있다.
우리가 저급언어를 자주사용하지 않지만 하드웨어와 밀접한 프로그램을 개발하는 임베디드 개발자나 게임 개발자, 정보 보안 분야 등의 개발자들은 어셈블리어를 많이 사용한다.
2. 컴파일 언어와 인터프리터 언어
소스코드가 명령어로 변환되는 방식은 크게 컴파일 방식과 인터프리트 방식이 있다.
두개의 방식이 나누어져 있는 이유는 프로그래밍 언어마다 변환 방식이 다르기 때문이다.
컴파일 방식을 사용하는 언어는 컴파일 언어라고 하며,
인터프리트 방식을 사용하는 언어는 인터프리터 언어라고 한다.
두 방식의 차이점은 무엇일까?
- 컴파일 언어
대표적인 언어 : C
컴파일 언어로 컴파일러에 의해 작성된 소스코드 전체가 저급언어로 변환되는 과정을 거친다.
이 과정을 컴파일이라고 한다.
간단히 생각해보면, 컴파일러에 의해 1차적으로 소스코드의 오류나 실행 가능여부를 확인한뒤 저급언어로 변환 한다는 것이다. 이때 오류가 하나라도 발생하면 컴파일에 실패한다.
컴파일이 성공하면 소스코드는 저급언어로 변환되며, 변환된 저급언어를 목적코드라고 한다.
- 인터프리터 언어
대표적인 언어 : Python
인터프리터 언어는 소스코드 전체가 저급 언어로 변환되는 컴파일 언어와 달리, 인터프리터에 의해 소스코드의 한줄한줄씩 실행된다.
한줄씩 실행되기 때문에 소스코드 전체를 저급언어로 변환하는 시간을 기다릴 필요가 없다.
만약 소스코드의 n번째 줄에서 오류가 발생해도 n-1번째 줄은 정상 실행된다.
결론적으로 컴파일 과정이 없고 바로바로 실행되는 인터프리터 언어가 빠르다고 생각 할 수 있지만,
컴파일이 성공적으로 끝났다는 가정하에 목적코드는 한줄씩 읽어야하는 인터프리터 언어보다 빠르게 실행된다.
따라서 인터프리터 언어가 컴파일 언어보다 느리다.
컴파일과 인터프리트 방식의 목적은 결국 컴퓨터가 이해하기 쉬운 저급언어로 변환하는 것이다.
저급언어는 명령어들로 이루어져있으며, 이번에는 이 명령어들이 어떤 구조를 가지고 있는지 알아보겠다.
3. 연산코드, 오퍼랜드
명령어는 연산코드와 오퍼랜드로 이루어져 있다.
연산코드는 쉽게 이야기하면, 어떤 작동을 나타내며,
오퍼랜드는 쉽게 이야기하면, 작동에 필요한 데이터이다.
먼저 오퍼랜드에 대해서 알아보겠다.
오퍼랜드에는 연산에 필요한 데이터들이 저장되며,
데이터가 직접 올 수도 있고 데이터를 참조한 주소가 올 수도 있다.
주로 참조 주소가 저장되기 때문에 주소 필드라고도 부른다.
오퍼랜드는 1개 이상 구성된다.
오퍼랜드의 개수에 따라 명령어를 다음과 같이 부른다
1. 오퍼랜드가 0개인 경우 : 0-주소 명령어
2. 오퍼랜드가 1개인 경우 : 1-주소 명령어
3. 오퍼랜드가 2개인 경우 : 2-주소 명령어
...
다음으로 연산코드이다.
연산코드는 명령어가 수행할 연산을 의미하며, 기본적으로 4가지의 유형으로 나눌 수 있다.
1. 데이터 전송
2. 산술/논리 연산
3. 제어 흐름 변경
4. 입출력 제어
네가지 유형에 따른 수많은 명령어가 존재하며 이는 CPU의 종류마다 차이점이 있다.
4. 주소 지정 방식
오퍼랜드 필드에는 대부분 데이터를 참조하는 주소가 온다.
이때 참조 가능한 데이터는 메모리 내에 있는 데이터 뿐만아니라 CPU의 레지스터도 포함이다.
여기서 의문이 생길 수 있다.
왜 오퍼랜드에는 데이터 자체를 사용하지 않는가?
이유는 명령어의 길이 때문이다.
명령어는 연산코드와 오퍼랜드로 구성되어있다.
명령어의 크기가 n비트이고 연산코드의 크기가 m비트라고 가정해보자.
오퍼랜드필드가 사용할 수 있는 크기는 n-m 비트이며, 오퍼랜드는 1개 이상으로 구성될 수있다.
즉 오퍼랜드가 a개로 구성되어있다면, 각 오퍼랜드에 할당된 크기는 (n-m)/a 이다.
이러한 제한적인 크기 때문에 오퍼랜드 필드에는 오퍼랜드의 참조 주소값이 들어온다.
이처럼 오퍼랜드 필드에 데이터가 저장된 위치를 명시할 때 연산에 사용할 데이터 위치를 찾는 방법을 주소 지정방식이라고 한다.
대표적인 주소지정방식 다섯가지에 대하여 알아보겠다.
- 즉시주소지정방식
연산에 사용할 데이터를 오퍼랜드 필드에 직접 명시하는 방법으로 가장 간단한 형태이다.
단점은 앞에서 언급하였듯 부족한 데이터 크기이며, 장점은 데이터를 찾는 과정이 없어 빠르다.
- 직접주소지정방식
오퍼랜드 필드에 유효주소를 직접적으로 명시하는 방식이다.
즉시주소지정방식보다는 명시할 수 있는 데이터 크기가 크지만, 오퍼랜드 필드의 길이가 연산코드의 길이만큼 짧아져 표현할 수 있는 유효주소에 제한이 생길 수 도 있다.
- 간접주소지정방식
유효주소의 주소를 오퍼랜드 필드에 명시하는 방식이다.
직접주소지정방식보다 표현할 수 있는 유효주소의 범위가 넓어졌지만 두번의 메모리 접근이 필요하여 일반적으로 다른방식보다 느리다. 제한적인 오퍼랜드 필드의 크기를 메모리의 주소를 빌려 여유있게 사용한다고 생각하면 이해가 빠르다.
- 레지스터주소지정방식
레지스터 주소지정방식은 직접주소지정방식과 비슷하지만 레지스터에 저장된 데이터를 오퍼랜드필드에 직접 명시한다.
일반적으로 CPU 외부에 있는 메모리에 접근하는 것보다 내부에 있는 레지스터에 접근하기 때문에 빠르게 데이터에 접근할 수 있으며 표현할 수 있는 레지스터 크기에 제한이 생길 수 있다는 단점이 있다.
- 레지스터간접주소지정방식
연산에 필요한 데이터를 메모리에 저장하고 그 주소를 저장한 레지스터를 오퍼랜드필드에 명시하는 방법이다.
메모리 접근횟수가 간접주소지정방식은 2번이지만 레지스터간접주소지정방식은 1번이기 때문에 상대적으로 빠르다.
'Computer Science' 카테고리의 다른 글
CS - #4. ALU, 제어창치, 레지스터 (0) | 2023.09.20 |
---|---|
CS - #2. 2진법, 16진법 표현 (0) | 2023.09.11 |
CS - #1. 컴퓨터 구조 (0) | 2023.09.10 |