본문으로 건너뛰기

저급언어, 고급언어

· 약 14분
brown

Intro

최근 이부분에 대해 정리하고 싶기도 했고,

최근에 애플은 왜 인텔 대신 ARM을 선택했나? 10분 순삭 해당 영상을 재밌게 봐서 한번 쭉 정리 한다.

여러 레퍼런스들이 이진코드와 기계어를 혼용해서 사용하는 느낌이다.

저급 언어(Low-Level Language)


  • 기계 중심의 언어
  • 실행 속도가 빠름
    • 이 부분은 사람이 작성한 코드가 컴파일러의 각종 최적화를 이겼을때나 가능...

기계어(Machine Language)


기계어는 2진법으로 구성된, 컴퓨터가 직접 해독하고 실행 할 수 있는 명령어 세트 프로그램을 나타내는 가장 낮은 단계의 언어 CPU에 따라 기계어가 다르다(각 기계마다 규약된 숫자들의 규칙 조합)

결국 프로그램이란 0과 1로 된, 컴퓨터에게 어떤 동작을 실행하라는 명령어들의 집합이고, 모든 언어들은 기계어로 변환된다.

  • 이 프로그램이란 것을 실행시키게 되면
  • 프로그램이라 불리는 명령어들이 메인 메모리(RAM 램)에 배치된다. 이 상태를 프로세스라고 부른다.
  • 이 배치된 명령어들을 하나씩 순서대로, 혹은 지정된 주소에 있는 명령어들을 읽어와서 CPU에서 계산 및 처리를 하게 되고
  • 명령어에 따라 CPU가 다른 컴퓨터 자원들의 동작, 수행을 명령한다.

바이너리 코드란?(Binary code)

  • 바이너리 코드는 컴퓨터가 인식할 수 있는 0과 1로 구성된 이진코드를 의미
  • 기계어는 0과 1로 이루어진 바이너리 코드이다.
  • 기계어가 이진코드로 이루어졌을 뿐이지 모든 이진코드가 기계어인 것은 아니다.(바이너리 코드 != 기계어)

바이트 코드란?(Byte Code)

  • CPU가 이해할 수 있는 언어가 기계어 라면 바이트 코드가상 머신에서 이해할 수 있는 이진 코드
  • 하드웨어가 아닌 소프트웨어에 의해 처리되기 때문에, 보통 기계어보다 더 추상적이다.
  • 역사적으로 바이트코드는 대부분의 명령 집합이 0개 이상의 매개 변수를 갖는 1byte 크기의 명령 코드(opcode)였기 때문에 바이트코드라 불리게 되었다.
  • 바이트코드는 특정 하드웨어에 대한 의존성을 줄이고, 인터프리팅도 쉬운 결과물을 생성하고자 하는 프로그래밍 언어에 의해, 출력 코드의 한 형태로 사용된다.
  • 컴파일되어 만들어진 바이트코드특정 하드웨어의 기계 코드를 만드는 컴파일러의 입력으로 사용되거나, 가상 머신에서 바로 실행된다.
  • Compile로 생성된 기계어 코드만으로 바로 실행되지는 않는 편
  • 대부분의 애플리케이션 로직에는 사용자가 직접 작성한 소스 코드 + 상당히 많은 라이브러리를 이용 혹은 만들어 활용 한다.
  • 이러한 라이브러리를 Application과 연결해 주는 작업 ==  링크(link)
  • 링크(link)여러 개의 오브젝트파일을 하나의 실행파일로 묶어주는 것이라고 보면 된다.
  • 운영체제에 관한 부분도 링크가 처리해준다.
  • 링크를 실행해주는 프로그램으로 링커(Linker)가 있다.
    • 정적링크(static link)
      • 컴파일된 소스파일을 연결해서 실행가능한 파일을 만드는 것
    • 동적링크(dynamic link)
      • 프로그램 실행 도중 외부에 존재하는 코드를 찾아서 연결

빌드(Build) = 컴파일(Compile) + 링크(Link)

빌드(Build): 컴파일(Compile)된 소스코드에 필요한 파일을 링크(Link) 시켜주는 것이다.

어셈블리어(Assembly language)


  • CPU 에는 해당 프로세서에 명령을 내리기 위해 고유의 명령어 세트가 마련되어 있는데 이 명령어 세트를 기계어라고 한다.
  • 이 기계어는 숫자들의 규칙조합임으로 프로그래밍에 상당히 난해하다.
  • 그래서 이 기계 명령어를 좀더 이해하기 쉬운 기호 코드로 나타낸것(기계어와 1:1로 대응된 명령을 기술하는 언어)이 어셈블리어이다.
  • 어셈블리어는 기계어를 알파벳으로 변환한 것이므로 어셈블리어를 배우는게 기계어를 배우는 것이다.
  • 어셈블리 언어는 그 코드가 어떤 일을 할지를 추상적이 아닌, 직접적으로 보여준다. 논리상의 오류나, 수행 속도, 수행 과정에 대해 명확히 해준다는 점에서 직관적인 언어이다.
  • 컴퓨터 시스템&구조를 좀 더 깊게 이해하고, 메모리상의 데이터나 I/O기기를 직접 액세스 하는등의 고급언어에서는 할 수 없는 조작을위해서이다. 프로그램의 최적화 및 리버스 엔지니어링을 위해서도 필요할 수 있다.
  • 어셈블리어를 기계어로 번역하는 프로그램이 제공되는데 이 프로그램을 어셈블러(assembleer)라고 한다.

고급언어(High-Level Language)


사람 중심의 언어

  • 실행을 위해서는 번역하는 과정이 필요함
  • 상이한 기계에서 소스 수정 없이 실행이 가능함

프로그래밍 언어의 문법 구조가 기계어와 유사하면 저급 언어(Low-Level Language)라고 부르고 사람들이 이해하기 편하도록 만들어진 프로그래밍 언어를 고급 언어라고 한다.

여기서 사용하는 High, Low의 의미는 사람의 언어에 가까운지, 기계의 언어에 가까운지를 표현하는 것일 뿐 성능의 좋고 나쁨을 이야기하는 용어가 아니다.

컴파일러(Compiler)


컴파일이란 어떤 언어의 코드를 다른 언어로 변환하는 과정이다.

원시 코드 -> 목적 코드

그리고 이것을 자동으로 수행해주는 소프트웨어를 컴파일러라고 한다.

  • compiler in general -> 고수준 언어를 저수준 언어로 변환
  • transcompiler or source-to-source compiler -> 비슷한 수준의 추상화를 가진 다른 언어로 변환 -> Transpile
    • 파스칼 ->  C
    • TypeScript -> JavaScript
    • 높은 버전의 자바스크립트 코드 -> 낮은 버전의 자바스크립트로 변환(Babel)
  • decompiler ->  저수준 언어고수준 언어로 변환

인터프리터(Interpreter)


소스코드를 바로 실행하는 프로그램 또는 환경을 말한다.

인터프리터는 다음의 과정 가운데 적어도 한 가지 기능을 가진 프로그램이다.

  1. 소스 코드를 직접 실행한다.
  2. 소스 코드를 효율적인 다른 중간 코드로 변환하고, 변환한 것을 바로 실행한다
  3. 인터프리터 시스템의 일부인 컴파일러가 만든, 미리 컴파일된 저장 코드의 실행을 호출한다.

인터프리터 언어는 원시코드를 기계어로 변환하는 과정없이 한줄 한줄 해석하여 바로 명령어를 실행하는 언어를 말합니다. R, Python, Ruby와 같은 언어들이 대표적인 인터프리터 언어입니다.

인터프리터가 직접 한 줄씩 읽고 따로 기계어로 변환하지 않기 때문에 빌드 시간이 없습니다. Runtime 상황에서는 한 줄씩 실시간으로 읽어서 실행하기 때문에 컴파일 언어에 비해 속도가 느립니다.

컴파일러 언어 vs 인터프리터 언어


고급언어로 작성된 프로그램들을 실행하는 데에는 두 가지 방법이 있다.

  • 가장 일반적인 방법은 프로그램을 컴파일 하는 것이고,
  • 다른 하나는 프로그램을 인터프리터에 통과시키는 방법이다.

컴파일러 언어

  • 전체 파일을 스캔하여 한꺼번에 번역
  • 초기 스캔시간이 오래 걸리지만, 한번 실행 파일이 만들어지고 나면 빠르다.
  • 기계어 번역과정에서 많은 메모리를 사용한다.
  • 전체 코드를 스캔하는 과정에서 모든 오류를 한꺼번에 출력해주기 때문에 실행 전에 오류를 알 수 있다.(컴파일 오류)

대표적인 언어로 C,C++,JAVA 등이 있다.

인터프리터 언어

  • 프로그램 실행시 한 번에 한 문장씩 번역한다.
  • 한번에 한문장씩 번역후 실행 시키기 때문에 실행 시간이 느리다.
  • 컴파일러와 같은 오브젝트 코드 생성과정이 없기 때문에 메모리 효율이 좋다.
  • 프로그램을 실행시키고 나서 오류를 발견하면 바로 실행을 중지 시킨다. 실행 후에 오류를 알 수 있기 때문에 사용성이 문제가 될수 있다.(런타임 오류)

대표적인 언어로 Python, Ruby, Javascript 등이 있다.


참조