728x90

프로그램 제작 과정

사용하는 컴퓨터의 환경에 따라 프로그램을 만드는 과정이 달라집니다. C는 이식성이 있어서 Unix, Linux, MS-DOS, Windows, Macintosh OS 등의 환경에서 사용될 수 있습니다.

먼저, 공통적인 C 언어의 몇 가지 요소를 살펴봅시다. C 프로그램이 실행되기까지의 과정을 꼭 알아둬야 하는 것은 아니지만, 이것은 기초지식이며, 또한 C 프로그램을 만들기 위해 왜 이런 절차를 거치는지 그 이유를 이해하는 것에 도움이 됩니다.

C 언어 파일은 텍스트 파일로 저장해야 하며, 이 파일은 .c로 끝나야 합니다(예를 들면 first.c, second.c) 마침표(.) 앞부분을 기본명이라 하고, 마침표 뒷부분을 확장자라 합니다. 그러므로 위에서 first는 기본명이고 c는 확장자이며 둘을 합친 first.c가 파일 이름이 됩니다.

예제 1.1 - hello.c 프로그램

#include <stdio.h>
 
int main(void) {
    printf("Hello, World");
 
    return 0;
}
cs

구체적으로 설명하기 위해서 위와 같은 C 소스 코드가 들어있는 hello.c라는 파일이 있다고 가정해봅시다. 예제 1.2의 소스 코드 내용에 대해서는 크게 신경을 쓰지 않아도 됩니다.

오브젝트 파일, 실행 파일, 라이브러리
C 언어는 소스 코드 파일을 실행 파일로 변환시키기 위해 컴파일링과 링킹이라는 두 단계를 거칩니다. 컴파일러는 소스 코드를 중간 코드로 변환하고, 링커는 그것을 다른 코드와 결합해 실행 파일을 만듭니다. C는 이처럼 두 단계로 나누어 처리하므로 모듈화가 가능합니다. 각각의 모듈을 따로 컴파일한 후, 컴파일된 모듈을 나중에 링커를 이용해서 결합할 수 있습니다. 그러므로 하나의 모듈만 수정해야 할 경우에 나머지 다른 모듈은 다시 컴파일하지 않아도 됩니다. 또한, 링커는 라이브러리 코드를 가져와 프로그램에 결합하는 일도 합니다.

중간 파일을 만드는 방법은 여러 가지가 있으며 가장 널리 쓰이는 방식은 소스 코드를 기계어 코드로 변환시켜 결과를 오브젝트 파일로 저장하는 것입니다. 오브젝트 파일은 기계어 코드로 이루어져 있지만, 실행할 수 있는 것은 아닙니다. 소스 코드를 기계어 코드로 번역한 것일 뿐 아직 완전한 프로그램이 아닙니다.

먼저, 오브젝트 파일은 시동 코드가 없습니다. 이 코드는 프로그램과 운영체제의 인터페이스를 담당합니다. 예를 들면, IBM PC 호환 기종은 MS Windows와 Linux로 사용할 수 있습니다. 이들은 같은 하드웨어에서 운영되므로 시동 코드 역시 같을 것 같지만, 두 운영체제는 프로그램을 처리하는 방식이 서로 달라서 시동 코드 또한 다릅니다.

또한, 오브젝트 파일은 라이브러리 루틴을 위한 코드가 없습니다. 거의 모든 C 프로그램들은 표준 C 라이브러리의 루틴을 사용하며, 이것을 함수라고 합니다. hello.cprintf() 함수를 사용하고 있는데, 오브젝트 코드 파일은 printf() 함수를 사용하라 지시하는 명령만 가지고 있을 뿐, printf()의 실제 코드를 포함하고 있지는 않습니다.

링커의 역할은 이 세 가지 요소(오브젝트 코드, 시동 코드, 라이브러리 코드)를 묶어서 하나의 파일 즉, 실행 파일로 만드는 것입니다.

정리하면, 오브젝트 파일과 실행 파일은 둘 다 기계어 명령들로 이루어져 있습니다. 오브젝트 파일은 사용자가 작성한 소스 코드를 기계어로 번역한 것입니다. 실행 파일은 소스 코드에서 사용한 라이브러리 루틴에 대한 기계어 코드와 시동 코드를 포함하고 있습니다.


Unix 시스템

C 언어는 Unix 시스템에서부터 시작되었으니 Unix부터 살펴보도록 하겠습니다.

Unix 시스템에서의 편집
C 언어는 자체적인 에디터를 갖고 있지 않아서 Emacs, vi 또는 X Windows System 환경의 텍스트 에디터와 같은 Unix 에디터 중 하나를 사용해야 합니다.

프로그램을 저장할 소스 파일에 유효한 이름을 부여하고, 프로그램을 정확하게 입력해야 합니다. 파일의 이름은 .c로 끝나야 하며, Unix는 대소문자를 구별하므로 hello.c Hello.c HELLO.C는 서로 다른 프로그램들입니다. 또한, HELLO.C는 소문자 c가 아닌 대문자 C를 사용했으므로 소스 파일의 이름이 될 수 없습니다.

Unix의 에디터를 이용해서 아래 내용을 입력하고, hello.c라는 이름으로 저장합니다.

#include <stdio.h>
 
int main(void) {
    printf("Hello, World");
 
    return 0;
}
cs

이 텍스트가 소스 코드이고, hello.c는 소스 파일입니다. 여기서 중요한 것은, 소스 파일을 적었다고 C 프로그래밍이 끝난 것이 아니라는 것입니다.

Unix 시스템에서의 컴파일
위에서 작성한 프로그램은 C 언어의 규칙에 맞게 작성했지만, 컴퓨터는 이해하지 못합니다. 컴퓨터는 #includeprintf()와 같은 것들을 알지 못하기 때문에 컴퓨터가 이해할 수 있는 코드(기계어 코드)로 번역해야 하는데, 그러기 위해서는 컴파일러의 도움이 필요합니다. 컴파일하면 실행 파일이 만들어지며, 컴퓨터가 작업하는 데 필요한 기계어 코드가 들어있습니다.

처음에는 cc 명령으로 Unix의 C 컴파일러를 실행했습니다. 하지만 Unix C 컴파일러는 발전하는 표준을 따라가지 못해 더는 사용되지 않고, 다른 사용자들이 만든 컴파일러를 사용하고 있습니다. 컴파일러의 종류는 바뀌었지만, 여전히 컴파일러를 실행시키는 명령으로 cc가 사용됩니다.

Unix 환경에서 hello.c 프로그램을 컴파일하려면 다음과 같이 입력해야 합니다.

cc hello.c

컴파일이 완료되면 Unix 프롬프트가 다시 나타납니다. 만약 프로그램을 작성할 때 실수했다면 경고 메시지 혹은 에러 메시지가 나올 수도 있습니다. (간혹 C 컴파일러가 ANSI C를 지원하지 않아 void라는 단어에 에러가 날 수 있습니다. 조만간 C 표준에 대해 설명할 테니 그때까지 소스 코드에서 void라는 단어를 빼주세요) 파일들의 리스트를 보여주는 ls 명령을 사용하면 a.out이라는 파일이 생성된 것을 볼 수 있습니다. (아래 그림 참조) 이 파일이 바로 실행 파일입니다. 아래 명령을 입력하면 이 실행 파일을 실행시킬 수 있습니다.

a.out

위 명령을 입력하면 다음과 같은 내용이 출력됩니다.

Hello, World

이 실행 파일(a.out)은 다음 프로그램을 컴파일할 때 새로운 a.out으로 덮여 쓰이기 때문에 이 파일을 보관하기 위해서는 파일의 이름을 바꿔야 합니다.

그러면 실행 파일 전에 생성된다 했던 오브젝트 파일은 어디에 있을까요? cc 컴파일러는 소스 파일과 기본명이 같으며, 확장자가 o인 오브젝트 파일을 만듭니다. 그렇다면 위의 예제를 컴파일할 때 hello.o라는 이름의 오브젝트 파일이 생성되어야 하지만, 그 파일을 리스트에서 찾을 수 없는 이유는 실행 파일을 만들고 난 후 링커가 그 오브젝트 파일을 삭제해 버렸기 때문입니다.

728x90
728x90