코딩 ·

C언어 컴파일과 Windows·Linux 환경의 차이

C언어로 작성한 소스 코드는 컴퓨터가 바로 실행할 수 있는 형태가 아니다. 사람이 이해하기 쉬운 C언어 문법으로 작성된 코드를 컴퓨터의 CPU가 처리할 수 있는 기계어 프로그램으로 변환해야 하는데, 이 과정을 컴파일 이라고 한다. 일반적인 C언어 컴파일 과정은 전처리, 컴파일, 어셈블, 링크의 순서로 진행된다. 전처리 단계에서는 #include, #define과 같은 전처리 지시문을 처리한다. 그다음 컴파일 단계에서 C언어 코드를 어셈블리 코드로 변환하고, 어셈블 단계에서 이를 목적 파일로 만든다. 마지막 링크 단계에서는 목적 파일과 필요한 라이브러리를 결합하여 실행 파일을 생성한다. GCC 공식 문서에서도 컴파일 과정이 전처리, 컴파일, 어셈블, 링크의 네 단계로 구성될 수 있다고 설명한다.

예를 들어 다음과 같은 `main.c` 파일이 있다고 가정할 수 있다.

 

#include <stdio.h>

int main(void) {
    printf("Hello, C!\n");
    return 0;
}


Linux에서는 일반적으로 GCC 또는 Clang과 같은 컴파일러를 사용한다. GCC를 사용할 경우 터미널에서 다음과 같이 입력할 수 있다.

bash
./main

 

 

Linux 실행 파일은 확장자가 반드시 필요한 것은 아니다. 따라서 `main.exe`가 아니라 단순히 main 이라는 이름으로도 실행 파일을 만들 수 있다. GCC 대신 Clang을 사용한다면 `clang main.c -o main`과 같이 작성할 수 있다. Clang도 전처리, 구문 분석, 최적화, 코드 생성, 어셈블, 링크 과정에 필요한 도구를 제어하는 C언어 컴파일러이다.

 

Windows에서는 Microsoft Visual Studio에 포함된 MSVC 컴파일러를 대표적으로 사용할 수 있다. MSVC의 명령줄 컴파일러 이름은 `cl.exe`이며, C와 C++ 소스 코드의 컴파일 및 링크 작업을 제어한다. 일반 명령 프롬프트가 아니라 Visual Studio 개발자 명령 프롬프트에서 다음과 같이 입력한다.

```cmd
cl main.c
```

이 명령을 실행하면 일반적으로 목적 파일인 `main.obj`와 Windows 실행 파일인 `main.exe`가 만들어진다. 프로그램은 다음과 같이 실행할 수 있다.

```cmd
main.exe
```

Microsoft 공식 문서에서도 `cl.exe`를 이용해 C 소스 파일을 컴파일할 수 있으며, 여러 개의 소스 파일을 한꺼번에 지정하거나 컴파일과 링크를 분리하여 실행할 수 있다고 설명한다.

Windows와 Linux의 가장 눈에 띄는 차이는 생성되는 파일의 형식이다. Windows의 실행 파일은 일반적으로 `.exe` 확장자를 가지며 PE, 즉 Portable Executable 형식을 사용한다. Windows에서 사용되는 목적 파일은 주로 `.obj` 확장자와 COFF 형식을 사용한다. Microsoft의 PE 형식 문서는 Windows 운영체제의 실행 파일과 목적 파일이 각각 PE와 COFF 구조를 사용한다고 명시한다.

반면 Linux에서는 목적 파일에 주로 `.o` 확장자를 사용하고, 실행 파일과 목적 파일 및 공유 라이브러리에는 ELF 형식이 사용된다. ELF 파일 내부에는 프로그램 헤더, 섹션 헤더, 동적 링크 정보, 재배치 정보, 심벌 테이블 등이 저장될 수 있다. Linux의 `readelf` 명령을 사용하면 이러한 ELF 형식 파일의 정보를 확인할 수 있다.

동적 라이브러리 형식도 서로 다르다. Windows에서는 동적 연결 라이브러리에 주로 `.dll` 확장자를 사용한다. DLL은 다른 프로그램이나 DLL에서 사용할 수 있는 함수와 데이터를 포함하는 모듈이다. Windows API의 여러 기능도 DLL을 통해 제공된다. Linux에서는 동일한 목적의 공유 라이브러리에 주로 `.so` 확장자를 사용한다. 두 환경 모두 프로그램이 외부 라이브러리의 기능을 사용하도록 할 수 있지만, 라이브러리 파일의 형식과 링크 방식, 검색 경로 및 운영체제의 로더가 동작하는 방식은 서로 다르다.

또 다른 차이는 사용할 수 있는 운영체제 전용 기능이다. `printf`, `strlen`, `malloc`과 같이 C 표준 라이브러리에 포함된 기능을 중심으로 작성한 프로그램은 비교적 다른 운영체제로 옮기기 쉽다. 그러나 Windows API, DLL, POSIX 함수, Linux 시스템 호출처럼 특정 운영체제에서 제공하는 기능을 직접 사용하면 소스 코드를 수정하지 않고 다른 운영체제에서 그대로 컴파일하기 어려울 수 있다. GNU C Library는 ISO C 표준의 라이브러리 기능뿐만 아니라 POSIX와 GNU 시스템에 특화된 추가 기능도 제공한다. 반대로 Windows 프로그램은 Windows API와 Microsoft에서 제공하는 런타임 및 라이브러리에 의존할 수 있다.

정리하면 C언어의 기본적인 컴파일 원리는 Windows와 Linux에서 동일하다. 두 환경 모두 전처리, 컴파일, 어셈블, 링크 과정을 거쳐 실행 가능한 프로그램을 생성한다. 그러나 Windows에서는 MSVC의 `cl.exe`, `.obj`, `.exe`, PE·COFF, DLL 등이 대표적으로 사용되고, Linux에서는 GCC 또는 Clang, `.o`, ELF 실행 파일, `.so` 등이 주로 사용된다. 따라서 두 운영체제의 차이는 C언어 자체보다는 사용하는 컴파일러와 명령어, 실행 파일 형식, 라이브러리, 운영체제 API에서 발생한다. 운영체제에 종속적인 기능을 최소화하고 표준 C 문법과 표준 라이브러리를 중심으로 프로그램을 작성하면 Windows와 Linux 모두에서 컴파일할 수 있는 이식성 높은 프로그램을 만들 수 있다.

'코딩' 카테고리의 다른 글

라즈베리파이로 집에서 서버 만들기  (0) 2024.06.12
러스트  (0) 2024.03.14