일단 C에서 컴파일링을 할 수 있는 두 가지 방법은 clang
과 make
둘의 차이점은 clang <파일이름> l<라이브러리 이름>
처럼, 파일이름을 쓰고 그 옆에 l
즉 "링크"와 함께 사용중인 라이브러리를 명시해줘야 한번에 컴파일을 한다. 반면에, make
는 이 모든 것을 자동으로 실행시켜 준다.
예시 코드
#include <cs50.h> // CS50 팀에서 만든 자체 라이브러리
#include <stdio.h>
int main(void)
{
string name = get_string("What's your name?/n");
printf("hello., %\n", name);
}
일단 clang
이나 make
로 컴파일이 시작되면, 예시코드 맨 윗줄에 적힌 <cs50.h>
라이브러리의 해당 코드를 가져와 말 그대로 내가 가 쓴 파일에 "붙여넣기"를 한다. 또 그 다음 줄 <stdio.h>
도 stdio.h
파일 내의 해당하는 코드를 소스코들로 가져와 붙여넣는다.
오?? 놀라움. 새로운 세상을 보는 듯...!
두번째 단계인 "컴파일"과정에서는 우리가 쓴 소스코드가 소스코드와 기계어의 중간단계인 "어셈블리어"로 변환되는데
위 소스 코드는,
main:
.cfi_startproc
# BB#0:
pushq %rbp
.Ltmp0:
.cfi_def_cfa_offset 16
.Ltmp1:
.cfi_offset %rbp, -16
movq %rsp, %rbp
.Ltmp2:
.cfi_def_cfa_register %rbp
subq %16, %rsp
xorl %eax, %eax
movl %eax, %edi
movabsq $.L.str, %rdi
movb $0, %al
callq get_string
movabsq $.L.str.1, %rdi
movq %rax, -8(%rbp)
mpvq -8(%rbp), %rsi
movb $0, %al
callq printf
...
이렇게, 우리가 알아 볼 수 없는 말로 번역된다(정확히 얘기하면 이제 껏 본 적 없는 언어로..!!)
와우!! C의 탄생은 어마어마 한 것이었구나!!??
화면의
pushq, movq, xorl, movabsq, callq
등의 코드는 명령어"인데, 인텔, AMD같은 회사들이 만든 CPU가 실제로 이해하는 건 바로 위에 나열한 명령어 같은 아주 "Low-level"(기계어에 더 가까운) 명령어 라고 한다.
이 명령어가 메모리에 저장, 복사, 화면에 내용 표시 등을 담당하지만, "C"에서는 clang
이 이 일을 해주는 것이다!
일단 이렇게 "어셈블리어"가 생기면, 이제 0과 1로 이루어진 Machine Code 즉 "기계어"로 바꾸어야 한다. 그것이 바로 clang
수행하는 "어셈블링" 이라고 한다.
만약에 <stdio.h>
, <cs50.h>
와 같은 라이브러리를 썼다면, (1)소스코드를 먼저 기계어로 번역, (2) 그 다음은 사용중인 라이브러리 파일들을(위의 예시코드로는 cs50.c
와stdio.c
파일) 기계어로 바꾼 후, (3) 이 것들을 하나로 "Link"(연결)한다고 한다.
결국 컴퓨터의 역사를 살펴보면
(1) 0,1 혹은 "켜짐", "꺼짐"으로 프로그래밍 시작
(2) 조금 더 인간언어에 익숙한 "어셈블리어"가 만들어지고
(3) 그 후에 C, C++, 파이썬, Ruby와 같은 언어들이 탄생하였다.
이렇게 프로그래밍 언어는 진화했다.
출처 : [부스트코스] 모두를 위한 컴퓨터 과학 (CS50 2019) (https://www.boostcourse.org/)