[혼공컴운] 1주차_컴퓨터구조, 데이터, 명령어 (with. 미션과 내 생각에 비추어 보는 것들)

·2024년 1월 7일
2

컴퓨터공학

목록 보기
1/6
post-thumbnail

1. 컴퓨터 구조 시작하기

컴퓨터 구조

모든 프로그램은 컴퓨터 푸품이 실행한다.

  • 컴퓨터 구조를 이해하면 문법만으로는 알기 어려운 성능/용량/비용을 고려하며 개발 할 수있다.

“내가 어떤 코드를 실행했을 때 어느 정도의 연산이 필요한지, 어느 정도의연산이 필요한지, CPU 파워, 속도 , 저장관리 비용을 짐작할 수 있다.”

컴퓨터구조에는 1. 컴퓨터가 이해하는 정보2. 컴퓨터의 네 가지 핵심 부품이 존재한다.

1) 컴퓨터가 이해하는 정보

프로그램을 이루는 두가지 정보는 데이터와 명령어다.

  • 데이터 : 명령어의 대상
  • 명령어 : 컴퓨터를 동작시키는 실질적인 정보

“컴퓨터는 명령어를 처리하는 기계"

2) 컴퓨터의 4가지 핵심 부품

아두이노, 라즈베리 파이와 같은 작은 컴퓨터부터 스마트폰, 노트북, 데스크톱, 서버 컴퓨터까지 다양한 종료의 컴퓨터에서 공통적인 핵심 부품

  • CPU : 명령어 해석, 실행하는 장치 “저장공간(메인 메모리)에서 명령어를 가져와서(인출_fetch) 해석하고 실행함(excute)”
    • 래지스터 : CPU 내부에 있는 작은 저장 자치로 여러개가 존재, 연산 결과를 잠깐 저장함
    • ALU : 계산기회로, 오버플로우를 검출
    • 제어장치 : 명령어를 해석하고 제어신호를 내보내 주는 장치(컴퓨터 부품에게 어떤 작업을 수행할지 알려주는 전기신호를 내보냄)
  • 메모리 : 실행 중인 프로그램을 저장하는 장치, 휘발성 메모리
    • 메인메모리 : 메인 메모리에 있는 데이터 저장 및 사용할 경우에 필요한 위치정보 주소라는 “유효 주소” 라는 개념 존재
    • 캐시메모리 : CPU와 보조메모리 사이를 보조하는 역할
  • 보조기억장치 : 보관할 프로그램을 저장하는 장치, 비휘발성 메모리
    • SSD,HSS 등으로 메인 메모리보다 용량이 더 크다.
  • 입출력 장치 : 컴퓨터 내외부와 정보를 주고받는 장치

  1. 메인보드(마더보드) : 컴퓨터 핵심 부품들을 연결하는 기판
  2. 시스템 버스 (버스) : 메인보드에 연결된 부품들이 서로 정보를 주고받을 수 있게함.
    • 주고 받는것이 무엇이냐에 따라 주소버스, 데이터버스, 제어버스가 존재
  3. CPU : 메모리에 저장된 명령어를 읽어 들이고, 읽어 들인 명령어를 해석하고, 실행하는 부품
    • CPU 내부 구성 요소로 가장 중요한 세 가지
      1. 산술논리연산장치(ALU; Arthmetic Logic Unit): 계산기, 컴퓨터 내부에서 수행되는 대부분의 계산 담당
      2. 레지스터 : 작은 임시 저장 장치, 여러개의 레지스터가 존재하고 각기 다른 이름과 역할을 가짐
      3. 제어장치 : 제어 신호라는 ㄱ전기신호를 내보내고 명령어를 해석하는 장치. 컴퓨터 부품들을 관리하고 작동시키기 위한 일종의 전기신호를 제어신호라 함.
        1. 메모리 읽기 제어 신호 : CPU가 메모리에 저장된 값을 읽음
        2. 메모리 쓰기 제어 신호 : CPU가 메모리에 어떤 값을 저장
  4. 메모리 : 현재 실행되는 프로그램의 명령어와 데이터를 저장하는 부품, 휘발성
  5. 보조기억장치 : 전원이 꺼져도 보관될 프로그램을 저장하기 위한 부품, 비휘발성
  6. 입출력장치 : 마이크, 스피커, 프린터, 마우스 등 처럼 컴퓨터 외부에 연결되어 컴퓨터 내부와 정보를 교환하는 장치

보조기억장치도 컴퓨터 외부에 연결되어 컴퓨터 내부와 정보를 교환할 수 있는 장치로 볼 수 있지않나?

⇒ 보조기억장치와 입출력장치를 ‘컴퓨터 주변에 붙어있는 장치’라는 의미에서 주변장치라 통칭하기도 한다. 다만, 보조기억장치는 다른 일반적인 주변장치와 달리 메모리를 보조한다는 특별한 기능을 수행하는 입출력 장치이다.

프로그램이 실행되려면 반드시 메모리에 저장되어 있어야 한다.

2. 데이터

컴퓨터는 0과 1만 이해한다

모든 “양수/ 음수/ 소수/ 문자”를 0과 1로 표현하는 방법은?

  • 양수 : 이진수
  • 음수 : 대부분 차용하는 방법은 2의 보수
  • 소수(분수) : 대부분 차용하는 방법은 부동소수점
  • 문자 : 문자 집합 & 인코딩
    • 문자 집합 : 컴퓨터가 이해할수 있는 문자들의 모임
    • 인코딩 : 0과 1로 변환하는 과정

정보단위

비트(bit)

제일 작은 정보단위는 비트(bit)

  • 비트는 0 또는 1, 두가지 정보를 표현할 수 있다.
  • 그러므로 경우의 수는 2^n 가지 정보를 표현할 수 있다.

바이트(byte)

1 바이트는 8개의 비트를 묶은 단위

워드(word)
CPU가 한 번에 처리할 수 있는 데이터 크기

  • CPU가 한 번에 16비트를 처리할 수 있따면 1워드는 16비트, 한 번에 32 비트를 처리할 수 있다면 1워드는 32비트
  • 하프 워드 : 워드의 절반 크기
  • 풀 워드 : 1배 크기
  • 더블 워드 : 2배 크기

CPU마다 워드 크기는다르지만 현대 컴퓨터의 워드 크기는 대부분 32비트 또는 64비트이다.

  • 인텔의 x86 : 32비트 워드 CPU
  • 인텔의 x64 : 64비트 워드 CPU

이진법_binary

숫자가 1을 넘어가는 시점에 자리 올림을 하여 0과 1만으로 모든 숫자를 표현하는 방법

  • 이진수 : 0과 1만으로 표현된 수
  • 뒤에 아래첨자(2) 또는 앞에 0b를 붙여 표현 (표현 하는 방법은 프로그래밍언어에 따라 다름)
방식십진수이진수
수학적 표기 방식81000(2)
코드상 표기 방식80b100

이진수의 음수 표현 - 2의 보수법

  • 0과 1만으로 음수를 표현하는 방법 중 하나
  • 어떤 수를 그보다 큰 2^n에서 뺀 값 예시) 100(2) - 11(2) = 01(2)

1. 1의 보수를 취하고 (1의 보수 : 모든 이지순의 0과 1을 뒤집는다.)
2. 거기에 1을 더한다.

1의 보수2의 보수
1011(2)0100(2)0101(2)
0101(2)1010(2)1011(2)

0과 1만으로 음수를 표현하면, 이진수로만 봐서는 양수와 음수를 구분하기 어렵지 않을까?
(양수로서의 0101(2)과 음수로서의 0101(2)이 구분가지 않는다.)

⇒ 컴퓨터 내부에서 어떤 수를 다루 때, 이 수가 양수인지 음수인지 구분하기위해 CPU 내부내에서 특별한 정보를 저장하는 플래그 레지스터를 사용한다.

십육진법

이진법은 0과 1로만 표현할 수 있기 때문에 너무 길어질 수가 있다.

1~9와 A~F로 모든 수를 표기하는 방법 (A =10, B=11, C=12, D=13, E=14, F=15)으로 15를 넘어가는 시점에 자리 올림하여 수를 표현하는 방법

  • 뒤에 아래첨자(16) 또는 앞에 0x를 붙여 표현

십육진수와 이진수는 서로 변환도 쉽고 편하다.

십육진수변환이진수
1A2B(16)0001(2) 1010(2) 0010(2) 1011(2)0001101000101011(2)
이진수변환십육진수
11010101(2)D(16) 5(16)D5(16)

문자 집합과 인코딩

문자 집합(charater set) : 컴퓨터가 인식하고 표현할 수 있는 문자의 모음

문자 인코딩 : 문자를 0과1로 이루어진 컴퓨터가 이해할 수 있는 문자코드로 변환하는 과정

문자 디코딩 : 0과 1로 이루어진 문자코드를 사람이 이해할 수 있는 문자로 변환하는 과정

문자가 깨진다면?

  • 지원되지않아서 컴퓨터가 이해할 수 없는 문자 집합
  • 호환되지 않는 인코딩 방식으로 데이터를 불러 들인 경우
  • 인코딩 방식과 디코딩 방식이 상이한 경우

아스키 코드(ASCII; American Standard Code for Information Interchange)

초창기 문자 집합 중 하나로, 영어 알파벳과 아라비아 숫자, 일부 특수문자를 포함한다.

  • 아스키 문자 집합에 속한 문자들은 각각 7비트로 표현 됨
    • 기본 8비트 = 오류검출 패리티 비트 (1비트) + 실제 문자 비트 (7비트)
  • 7비트로 표현할 수 있는 정보의 가짓수는 2^7로, 0부터 127까지 총 128개의 문자 표현 가능

아스키 문자 집합에 0부터 27까지 수가 할당되어 아스키 코드로 인코딩 된다.

#include <stdio.h>

int main() {
    printf("%d \n", 'a'); // 'a'의 ASCII 값 출력
    printf("%c \n", 97);  // ASCII 값 97에 해당하는 문자 출력

    return 0;
}

아스키 코드는 아스키 문자 집합외의 다양한 언어의 문자를 표현할 수가 없다.

8비트의 확장 아스키가 등장했지만, 그 또한 표현할 수 있는 문자 갯수가 256개로 한정적이다.

EUC-KR

완성형 인코딩 방식 기반의 한글 인코딩 방식

완성형 인코딩 방식 : 완성된 하나의 글자에 고유한 코드를 부여하는 인코딩 방식
조합형 인코딩 방식 : 초성, 중성, 종성을 위한 각각의 비트열을 할당하여 그것들의 조합으로 하나의 글자를 완성하는 인코딩 방식

유니코드와 UTF-8

여러 나라의 문자를 광범위하게 표현할 수 있는 통일된 문자 집합.

  • 대부분 나라의 문자, 특수문자, 화살표나 이모티콘 까지도 코드로 표현할 수 있다.

코드포인트 : U+<코드 포인트>

4자리의 16진수로, 유니코드 문자에 부여된 고유한 수

  • U+D55c, U+AE00

유니코드 인코딩 방식에는 utf-8m utf-16,utf-32 등이 존재하며, 이 인코딩 방식은 유니코드의 코드 포인트를 인코딩한다.

3. 명령어

컴퓨터는 명령어를 처리하는 기계

개발자가 작성한 소스코드가 어떻게 명령어로 변환될까?

컴퓨터는 소스코드를 이해할 수 있는가?

⇒ 컴퓨터는 명령어를 이해한다.
”소스코드는 실행되기 전에 명령어(재료는 데이터)로 변환되어서 실행된다.”

명령어와 데이터 : 컴퓨터가 이해하기 쉬운 언어, 저급언어

소스코드 : 개발자가 이해하기 쉬운 언어, 고급언어

저급언어

컴퓨터가 직접 이해하고 실행할 수 있는 언어

CPU와 컴파일러에 따라 달라질 수 있다.

1. 기계어 (machine code)

컴퓨터가 직접 이해하는 근원적인 언어로 0과 1의 명령어 비트로 이루어진 저급 언어

  • 이진수로 나열하면 너무 길어지기 때문에 가독성을 위해 십육진수로 표현하기도한다.

2. 어셈블리어(assembly language)

0과 1로 이루어진 기계어를 읽기 편한 형태로 번역한 저급언어

기계어어셈블리어
0101 0101push rbp
0101 1101pop rbp
1100 0011ret

고급언어

사람이 이해하고 작성하기 쉽게 만들어진 언어

고급언어에서 저급 언어로 변환되는 대표적인 방식

성능면 : 컴파일 > 인터프리트

1. 컴파일

컴파일 언어로 작성된 소스 코드는 컴파일러에 의해 저급 언어로 변환된다. (결과로 목적코드 생성)

  • 컴파일 도중 컴파일러가 소스 코드 내에서 오류를 하나라도 발견하면 해당 소스 코드는 컴파일에 실패함.
  • C, C++ , Rust etc.

2. 인터프리트

인터프리터에 의해 소스코드가 한 줄 씩 저급 언어로 변환되고 실행된다. (한 줄씩 목적코드 생성)

  • 인터프리트 도중 인터프리터가 소스 코드 내에서 오류를 발견하여도, 발생 전까지의 코드는 실행함.
  • python.javascript etc.

컴파일 / 인터프리트 오개념 주의

  • 소스코드가 저급 언어로 변환되는 대표적인 방식일뿐, 컴파일 방식과 인터프리트 방식은 칼로 자르듯 구분되는 개념이 아니다.
  • 컴파일 언어의 특성과 인터프리트언어의 특성을 다 갖춘 언어도 존재한다. (JAVA, python etc.)

목적 파일 : 목적 코드로 이루어진 파일, 컴퓨터가 이해하는 저급 언어

실행 파일 : 실행 코드로 이루어진 파일

목적 코드가 실행파일이 되기 위해서는 링킹이라는 작업을 거쳐야한다.

“소스 코드 ⇒(컴파일) ⇒ 목적 코드(목적 파일) ⇒ (링킹) ⇒ 실행 파일”

명령어 구조

명령의 대상, 동작

“무엇을 대상으로 무엇을 수행하라.” ⇒ 오퍼랜드로 연산코드를 수행하라.

연산코드오퍼랜드
무엇을 수행하라무엇을 대상으로
더해라100과120을
빼라메모리 32번지 안의 값과메모리 33번지 안의 값을
저장해라10을메모리 128번지에

명령어 : 연산코드 + 오퍼랜드

연산코드(연산자) : 오퍼랜드가 수행할 동작, ‘명령어가 수행할 연산’

  • 가장 기본적인 연산 코드 유형 : 데이터 전송, 산술/논리 연산, 제어 흐름 변경, 입출력 제어

오퍼랜드(피산연자, 주소필드) : ‘연산에 사용할 데이터’ 또는 ‘연산에 사용할 데이터가 저장된 위치’

  • 오퍼랜드 필드에는 숫자와 문자 등을 나타내는 데이터, 메모리나 레지스터 주소가 올수 있다.
  • 오퍼랜드 갯수는 유동적일 수 있다.
    • 0개 오퍼랜드 명렁어 : 0-주소 명령어
    • 1개 오퍼랜드 명령어 : 1-주소 명령어
    • 2개 오퍼랜드 명령어 : 2-주소 명령어

오퍼랜드 필드에는 연산에 사용할 데이터를 직접 명시하기보다는 많은 경우 데이터가 저장된 위치(주소)를 명시한다.

주소 지정 방식

연산코드에 대상이 되는 데이터가 명령어 상에 없을 때, 레지스터나 메모리에 데이터의 대상이 되는 곳에 찾아가는 방법

왜 데이터를 직접 명시하지 않고 위치를 명시할까?

⇒ 명령어의 길이는 한정되어있기 때문이다.

오퍼랜드가 많아 지게 되면, 각각의 오퍼랜드 필드 크기가 작아지게 된다. 하나의 오퍼랜드 필드로 표현할 수 있는 정보의 가짓수가 점점 줄어들게된다.

데이터가 아닌 데이터를 가리키는 레지스터나 메모리 주소가 담긴다면, 데이터의 크기는 오퍼랜드의 크기와 상관없이 하나의 메모리 주소에 저장할 수 있는 공간만큼 커진다.

유효주소 : 연산 코드에 사용할 데이터가 저장된 위치, 연산의 대상이 되는 데이터가 저장된 위치

즉시 주소 지정 방식

연산에 사용할 데이터를 오퍼랜드 필드에 직접 명시하는 방식

데이터의 한계점이 존재하지만, 연산 속도는 그 어느 것보다 빠르다.

직접 주소 지정 방식

오퍼랜드 필드에 유효 주소를 직접적으로 명시하는 방식

표현할 수 있는 오퍼랜드 필드의 길이가 연산 코드의 길이만큼 짧아져 표현할 수 있는 유효 주소에 제한이 생길 수도 있다.

간접 주소 지정 방식

유효 주소의 주소를 오퍼랜드 필드에 명시하는 방식

직접 주소 지정방식보다 표현할 수 있는 유효 주소의 범위가 더 넓다.

두 번의 메모리 접근이 필요하기 때문에 즉시 지주소 지정 방식, 직접 주소 지정 방식보다 느리다.

레지스터 주소 지정 방식

직접 주소 지정 방식과 유사하다.

연산에 사용할 데이터를 저장한 레지스터를 오퍼랜드 필드에 직접 명시하는 방법

일반적으로 CPU 외부에 있는 메모리에 접근하는 것보다 CPU내부에 있는 레지스터에 접근하는 것이 더 빠르다.

하지만, 직접 주소 지정방식이기 때문에 표현할 수 있는 레지스터 크기에 제한 생길 수 있다.

레지스터 간접 주소 지정 방식

연산에 사용할 데이터를 메모리에 저장하고, 그 주소(유효 주소)를 저장한 레지스터를 오퍼랜드 필드에 명시하는 방법

유효 주소를 찾는 과정이 간접 주소 지정방식과 유사하지만, 메모리에 접근하는 횟수가 한 번이기때문에 연산속도 더 빠르다.

💡 주소 지정 방식을 학습하면서 제일 먼저 떠오른 것은 자바스크립트 변수 메모리 할당이었다.

내가 생각하는 것으로 챗지피티한테 물어봤다.

“즉시 주소 지정방식과 간접 주소 지정방식을 보면서 자바스크립트가 원시타입과 참조타입을 저장하는 방식을 떠올랐어. 관련이 있을까?”


1주차 미션

혼자 공부하는 컴퓨터 구조+운영체제

  • 진도: Chapter 01 ~ 03
    기본 미션: p. 51의 확인 문제 3번, p. 65의 확인 문제 3번 풀고 인증하기
    선택 미션: p. 100의 스택과 큐의 개념을 정리하기

기본 미션: p. 51의 확인 문제 3번, p. 65의 확인 문제 3번 풀고 인증하기

선택 미션: p. 100의 스택과 큐의 개념을 정리하기

스택 (stack)

나중에 저장한 데이터를 가장 먼저 빼내는 데이터 관리방식 ( 후입선출; LIFO_Last In First Out)

  • 흔히 박스가 쌓인 형태
  • 한쪽 끝이 막혀 있는 통에 데이터를 쌓아두고(저장하고), 빼낼 때는 마지막으로 저장한 데이터부터 빼낸다.
연산설명
삽입(Push)스택에 데이터를 삽입
추출(Pop)스택에 데이터를 추출
class Stack {
  constructor() {
    //  스택을 초기화하고, 내부적으로 객체를 사용하여 요소들을 저장
    this.items = {};
    this.topIndex = 0; // 다음 요소가 들어갈 위치
  }

  //새 요소를 스택의 맨 위에 추가
  push(item) {
    this.items[this.topIndex] = item;
    this.topIndex++;
  }

  //스택의 맨 위 요소를 제거하고 반환
  pop() {
    if (this.topIndex > 0) {
      this.topIndex--;
      const item = this.items[this.topIndex];
      delete this.items[this.topIndex];
      return item;
    }
  }

  //스택의 맨 위 요소를 반환
  peek() {
    if (this.topIndex > 0) {
      return this.items[this.topIndex - 1];
    }
  }

  isEmpty() {
    return this.topIndex === 0;
  }

  getLength() {
    return this.topIndex;
  }
}

큐 (Queue)

가장 먼저 저장된 데이터부터 빼내는 데이터 관리 방식 (선입선출; FIFO_Fist In First Out)

  • 양쪽이 뚫려 있는 통과 같은 저장 공간에 한 쪽에는 데이터를 저장하고, 다른 한쪽으로는 먼저 저장한 순서대로 데이터를 빼낸다.
class Queue {
  constructor() {
    this.items = {}; // 큐의 요소를 저장하는 객체
    this.headIndex = 0; // 큐의 맨 앞 요소의 인덱스
    this.tailIndex = 0; // 큐에 다음 요소가 추가될 인덱스
  }

  enqueue(item) {
    this.items[this.tailIndex] = item; // 큐의 끝에 요소를 추가
    this.tailIndex++; // tailIndex 증가
  }

  dequeue() {
    if (this.headIndex !== this.tailIndex) {
      // 큐가 비어있지 않은 경우에만
      const item = this.items[this.headIndex]; // 맨 앞의 요소를 가져옴
      delete this.items[this.headIndex]; // 해당 요소를 큐에서 제거
      this.headIndex++; // headIndex 증가
      return item; // 제거된 요소 반환
    }
  }

  // 큐의 맨 앞 요소 반환 (제거하지 않음)
  peek() {
    return this.items[this.headIndex];
  }

 // 큐의 현재 길이 계산 
  getLength() {
    return this.tailIndex - this.headIndex;
  }
}

1주차 회고

혼공단 스터디 1주차 범위에 맞게 컴퓨터공학 인터넷 강의를 먼저 듣고, 책을 1회독 한뒤에 정리했다.
글 내용에도 있다시피 메모리 지정 방식에서는 정말 머릿속으로 유레카를 외쳤다.

배치업데이트로 이루어지는 리액트 상태 변화가, 사실상 컴퓨터공학의 한 부분의 지식이라는 것을 알때도 컴퓨터 공학 지식을 쌓아야하는데 라는 고민이 앞섰었다.
리액트를 볼때마다 하나의 작은 운영체제가 아닐까? 라는 생각은 은연중에 했었기 때문이다.

아 물론, 어떤 점에서 그렇게 생각하냐고 물어본다면 정확하게는 말하지는 못하겠다. 6주뒤에는 술술나오지 않을까?

믿거나 말거나

profile
성실하게

1개의 댓글

comment-user-thumbnail
2024년 1월 7일

담님 분철신청해서 책 늦게받은거치곤 열심히 작성하셨네용ㅋㅋㅋㅋ 잘보고갑니디👍🏻

답글 달기