[CS] 컴파일링, 디버깅

MOON HEE·2022년 8월 30일
0

Computer Science

목록 보기
7/15
post-thumbnail
/* 모두를 위한 컴퓨터 과학(CS50 2019) 정리본입니다. */

컴파일링의 4단계와 디버깅에 대해서 알아보자!


1. 컴파일링


가장 기본적인 코드구조를 통해 실행원리를 정리해보자.

#include <stdio.h>

int main(void)
{
	printf("hello, world\n");
}
  • main 함수는 프로그램의 시작점이다.

  • printf는 출력을 담당하는 함수이다. 이 함수를 사용하기 위해서는 stdio.h 라이브러리가 필요하다. stdio.h는 헤더파일로, C언어로 작성되어 있으며 파일명이 .h로 끝나는 파일이다.
    이 파일에는 printf 함수의 프로토타입이 있어 stdio.h는 Clang 컴파일러가 프로그램을 컴파일할 때 printf가 무엇인지 알려주는 역할을 한다.

  • 위키백과에서 프로토타입에 대해 찾아봤다. 강의에서 프로토타입이 뭔지 아직 제대로 설명해주지 않아서, 프로그래밍 언어에서의 의미보다는 일반적인 의미의 프로토타입이 무엇인지 일단 알아보았다. 프로토타입(prototype)은 원래의 형태 또는 전형적인 예, 기초 또는 표준이다. 시제품이 나오기 전의 제품의 원형으로 개발 검증과 양산 검증을 거쳐야 시제품이 될 수 있다. 프로토타입은 '정보시스템의 미완성 버전 또는 중요한 기능들이 포함되어 있는 시스템의 초기모델'이다.

  • 코드를 clang hello.c로 컴파일하고 ./a.out 명령으로 프로그램을 실행할 때 이과정은 컴퓨터가 이해하는 0과 1로 가득한 파일 a.out을 생성하여 실행 가능하게 한다.
    만약 a.out과 다른 이름(hello)으로 컴파일을 하고 싶다면 아래와 같이 명령행 인자를 추가해줘야 한다.

$ clang -o hello hello.c
$ clang -o hello hello.c -lcs50 // 라이브러리를 사용한 프로그램 컴파일할 때
$ make hello // 아주 간단하게 가능!

make나 clang을 사용해서 프로그램을 실행할 때 4단계를 거친다.

1-1. 전처리(Precompile)

  • 전처리기에 의해 전처리가 수행된다. #으로 시작되는 C 소스 코드는 전처리기에게 실질적인 컴파일이 이루어지기 전에 무언가를 실행하라고 알려준다. 예를 들어, #include는 전처리기에게 다른 파일의 내용을 포함하라고 알려준다. 프로그램의 소스 코드에 #include 같은 코드를 포함하면, 전처리기는 새로운 파일을 생성한다. 이 파일도 C 소스 코드 형태이고 stdio.h 파일의 내용이 #include 부분에 포함된다.

1-2. 컴파일(Compile)

C 코드를 컴퓨터가 알아들을 수 있는 언어(어셈블리어)로 변환하는 단계

  • 전처리기가 전처리한 소스 코드를 생성하고 나면 그 다음 단계는 컴파일이다. 컴파일러 프로그램은 C 코드를 어셈블리어라는 저수준 프로그래밍 언어로 컴파일한다. 어셈블리는 C보다 연산의 종류가 훨씬 적지만, 여러 연산들이 함께 사용되면 C에서 할 수 있는 모든 걸 할 수 있다. C 코드를 어셈블리 코드로 변환시켜줌으로써 컴파일러는 컴퓨터가 이해할 수 있는 언어와 최대한 가까운 프로그램으로 만들어 준다.

1-3. 어셈블(Assemble)

어셈블리어에서 오브젝트 코드로 변환하는 단계

  • 소스 코드가 어셈블리 코드로 변환되면, 다음 단계인 어셈블 단계로 어셈블리 코드를 오브젝트 코드로 변환시키는 것이다. 컴퓨터의 중앙처리장치가 프로그램을 어떻게 수행해야 하는지 알 수 있는 명령어 형태인 연속된 0과 1들로 바꿔주는 작업이다. 이 변환작업은 어셈블러라는 프로그램이 수행한다. 소스 코드에서 오브젝트 코드로 컴파일 되어야 할 파일이 딱 한 개라면, 컴파일 작업은 여기서 끝나고, 그렇지 않은 경우에는 링크라 불리는 단계가 추가된다.

만약 프로그램이 여러 개의 파일로 이루어져 있어 하나의 오브젝트 파일로 합쳐져야 한다면 링크라는 컴파일의 마지막 단계가 필요하다. 링커는 여러 개의 다른 오브젝트 코드 파일을 실행 가능한 하나의 오브젝트 코드 파일로 합쳐준다.


2. 디버깅


버그(bug)는 코드에 들어있는 오류다. 버그로 인해 프로그램의 실행에 실패하거나 프로그래머가 원하는 동작을 못하기도 한다. 디버깅(debugging)은 코드에 있는 버그를 식별하고 고치는 과정이다.

디버거는 프로그램을 특정 행에서 멈출 수 있게 해주기 때문에 버그를 찾는데 도움이 된다. 멈추는 지점을 중지점이라고 한다.

나는 개발할 때 VSC를 사용하고 있다. 아직 코린이라 디버깅 기능을 잘 사용해보지 못했다. 사용해보고 싶어서 클릭클릭해봐도 어떻게 사용하는 건지 아직 잘 모르겠다. 실제로 사용하는 환경을 확인해보고 싶어서 디버깅에 관한 내용은 드림코딩 강의를 참고해서 정리해봤다.

  • 디버깅에서 가장 중요한 것은 문제를 구체적으로 정의하는 거다. 그래야 그 문제에 관한 해결방법을 찾을 수 있다.
  • 원하는 or 기대하는 현상과 현재 일어나고 있는 일의 갭을 좁혀나가는 것이 디버깅이다.

2-1. VSC 디버거 기능

콘솔로그로 디버깅이 충분히 가능하지만, 좀더 동적으로 디버깅을 하기 위해 디버거를 사용한다.

  • 멈춰보고 싶은 곳(의심가는 곳)에 break point(빨간점)를 걸어놓는다.
  • 디버깅을 실행한다.
  • 상단 화살표(step over)를 클릭하면 한단계씩 실행해볼 수 있다.
  • 좌측에는 VARIABLES이 모여 있는데, 이곳에서 지역변수와 전역변수를 확인하여 디버깅을 해볼 수 있다. VARIABLES에서 값을 변경해서 확인해볼 수도 있다.
  • 그 아래 WATCH에서는 모든 변수가 아니라 특정한 변수만 확인하고 싶을 때 사용한다.
  • CALL STACK에서는 함수가 어떤 순서로 실행됐는지 확인할 수 있다.
  • 맨 아래 BREAKPOINTS에서는 내가 걸어 놓은 Break Point를 확인할 수 있다.
profile
자고 일어나면 해결되는게 더 많은 듯 그럼 잘까

0개의 댓글