Skip to main content

Command Palette

Search for a command to run...

[배열] 컴파일링

Published
•3 min read•View as Markdown
[배열] 컴파일링
W

안녕하세요! 프론트엔드 개발자 woodstock입니다.

저는 매일 조금씩 발전하고자 하는 마음으로 개발공부를 시작했고, 이 블로그는 그 과정에서 배우고 성장하는 이야기를 담고 있습니다.

여러분의 피드백과 조언은 언제나 환영합니다! 함께 배우고 성장하는 과정을 즐길 수 있기를 기대합니다.

우리가 작성한 C 코드를 실행하기 위해서는 컴파일링을 해줘야 한다.

C문법로 작성된 텍스트 형식의 파일은 컴파일링시 구체적으로 어떤 단계를 거쳐서 컴퓨터가 해석 가능한 파일로 변환될까?

#include <studio.h>

int main(void)
{
  printf("hello, world\n");
}

위 코드에서 main이라는 함수는 프로그램의 시작점으로써 실행 버튼을 클릭하는 것과 같고, printf는 출력을 담당하는 함수이다.

printf함수를 사용하기 위해서는 studio.h라이브러리가 필요하다.

studio.h는 c언어로 작성된 헤더파일로 printf함수의 프로토타입을 가지고 있어 Clang컴파일러가 프로그램을 컴파일할 때 printf가 무엇인지 알려주는 역할을 한다.

코드를 clang hello.c로 컴파일하고 ./a.out 명령으로 프로그램을 실행할 때 이 과정은 컴퓨터가 이해하는 0과 1로 가득찬 파일 a.out을 생성하여 실행 가능하게 한다.

만약 a.out과 다른 이름(hello)으로 컴파일을 하고 싶다면 아래와 같이 명령행 인자를 추가해야주면 된다.

clang -o hello hello.c


이 때 우리는 cs50 라이브러리를 사용했었다.

clang -o hello hello.c -lcs50

이는 clang에게 CS50 라이브러리에 있는 모든 0과 1들을 여기에 연결하라는 의미이다.

이전에 배웠던 make 프로그램을 이용하면 이 모든 컴파일 과정을 자동으로 더 간단하게 처리할 수 있다.

make나 clang을 사용해서 프로그램을 실행할 때에는 아래의 네 단계를 거친다. >

  • 전처리
  • 컴파일링
  • 어셈블링
  • 링킹


전처리(Precompile)

컴파일의 첫 번째 단계인 전처리는 전처리기에 의해 수행된다. # 으로 시작되는 C 소스 코드는 전처리기에게 실질적인 컴파일이 이루어지기 전에 무언가를 실행하라고 알려준다.

예를 들어, #include는 전처리기에게 다른 파일의 내용을 포함시키라고 알려주는 것이다. 프로그램의 소스 코드에 #include 와 같은 줄을 포함하면, 전처리기는 새로운 파일을 생성하는데 이 파일은 여전히 C 소스 코드 형태이며 stdio.h 파일의 내용이 #include 부분에 포함된다.

컴파일(Compile)

그 다음 단계는 컴파일로, 컴파일러라고 불리는 프로그램이 C 코드를 어셈블리어라는 저수준 프로그래밍 언어로 컴파일한다.

어셈블리는 C보다 연산의 종류가 훨씬 적지만, 여러 연산들이 함께 사용되면 C에서 할 수 있는 모든 것들을 수행할 수 있다. C 코드를 어셈블리 코드로 변환시켜줌으로써 컴파일러는 컴퓨터가 이해할 수 있는 언어와 최대한 가까운 프로그램으로 만들어 준다. 컴파일이라는 용어는 소스 코드에서 오브젝트 코드로 변환하는 전체 과정을 통틀어 일컫기도 하지만, 구체적으로 전처리한 소스 코드를 어셈블리 코드로 변환시키는 단계를 말하기도 한다.

어셈블(Assemble)

그 다음 단계는 어셈블로, 어셈블리 코드를 오브젝트 코드로 변환시키는 것이다. 컴퓨터의 중앙처리장치가 프로그램을 어떻게 수행해야 하는지 알 수 있는 명령어 형태인 연속된 0과 1들로 바꿔주는 작업이다.

이 변환작업은 어셈블러라는 프로그램이 수행하는데, 소스 코드에서 오브젝트 코드로 컴파일 되어야 할 파일이 딱 한 개라면, 컴파일 작업은 여기서 끝이 난다. 그러나 그렇지 않은 경우에는 링크라 불리는 단계가 추가된다.

만약 프로그램이 (math.h나 cs50.h와 같은 라이브러리를 포함해) 여러 개의 파일로 이루어져 있어 하나의 오브젝트 파일로 합쳐져야 한다면 링크라는 컴파일의 마지막 단계가 필요하다.

링커는 여러 개의 다른 오브젝트 코드 파일을 실행 가능한 하나의 오브젝트 코드 파일로 합쳐준다.

예를 들어, 컴파일을 하는 동안에 CS50 라이브러리를 링크하면 오브젝트 코드는 GetInt()나 GetString() 같은 함수를 어떻게 실행할 지 알 수 있게 된다.

이 네 단계를 거치면 최종적으로 실행 가능한 파일이 완성된다.

생각해보기

만약 컴파일링 과정을 거치지 않기 위해 바로 머신코드로 우리가 원하는 프로그램을 작성하려고 한다면 어떤 문제가 있을까?

정답

직접 머신코드로 프로그램을 작성하는 것은 복잡하고 시간이 많이 소요된다. 또한, 유지보수와 디버깅이 매우 어려워진다.

More from this blog

💥 new Array(length).map()으로 배열 초기화 시 콜백이 실행되지 않는 문제

JavaScript에서 배열을 초기화하려고 new Array(4).map(() => [])을 사용했는데 의도대로 동작하지 않았다. 원인을 찾아보니 JavaScript의 빈 슬롯과 undefined의 차이, 그리고 map() 메서드가 빈 슬롯에 대해 콜백을 실행하지 않는다는 특성때문이었다. 문제 상황 특정 크기의 배열을 만들고 각 요소를 []로 초기화 하려고 했다. const result = new Array(4).map(() => []); co...

Jun 28, 20252 min read17

💥 에러 메시지와 스택 트레이스 분석을 통해 문제 해결하기

JavaScript로 카드 게임 로직을 구현하던 중 TypeError: Cannot read properties of undefined라는 에러를 만났다. 코드가 복잡하고 짐작가는 부분이 단번에 떠오르지 않아 막막했는데, 에러 메세지와 스택 트레이스를 차근차근 분석해가며 원인을 찾아낸 과정을 기록해본다. 에러 발생 게임 로직을 테스트하던 중 특정 입력에서 다음과 같은 에러가 발생했다. TypeError: Cannot read properties...

Jun 25, 20254 min read11

🧐 적절한 함수명과 단일 책임으로 코드 개선하기

이 글에서는 JavaScript로 구현된 보드게임의 로직을 개선하는 과정을 다루며, 개선 과정은 함수명 개선 → 중복 제거 → 책임 분리의 단계로 이루어져있다. 작동하지만 개선이 필요한 코드 처음에 작성한 코드는 기능적으로는 문제없이 동작했지만, 더 나은 방식을 고민하다 보니 여러 개선점을 찾을 수 있었다. function checkLadder(position) { switch (position) { case 4: return 14;...

Jun 23, 20253 min read23

작심삼십일 - TypeScript 강의를 완강하다.

유데미 작심삼십일 챌린지에 참여하다 작심삼십일 챌린지는 유데미의 한국 런칭 3주년을 기념한 이벤트 중 하나로, 30일 동안 유데미 강의를 들으며 인증을 하는 챌린지이다.취업 준비를 하면서 여러가지 요인으로(주로 심리적이지만..) 학습 루틴이 망가졌던 찰나에 이 이벤트를 보게되었고, 마침 기존에 사두고 볼 엄두가 안 났던 타입스크립트 강의가 있었기에 옳다구나! 하고 신청했었다. 챌린지를 통해 무엇을 배웠나? 챌린지의 목표로 정한 강의는 유데미에...

Nov 18, 20242 min read58
작심삼십일 - TypeScript 강의를 완강하다.

woodstock's devlog

215 posts

안녕하세요! 프론트엔드 개발자 woodstock입니다.

제 블로그에서는 프론트엔드 개발에 대한 다양한 주제를 다룹니다.

JavaScript, TypeScript, React, Next.js 등의 기술을 활용하여 실제 프로젝트를 진행하면서 얻은 경험과 지식을 공유하고자 하며, 컴퓨터 과학(CS)의 기본 개념과 알고리즘, 자료구조 등에 대해서도 다룹니다.