Journey to Security/C언어

C언어 운영체제별로 조건부 컴파일하기

Cordilog 2026. 2. 25. 18:10

지난 포스팅에서 #ifdef를 이용해서 운영체제의 비트 수(32bit vs 64bit)에 따른 조건부 컴파일 방법에 대해 알아봤다. 

운영체제의 비트 수 외에도 C언어는 운영체제(OS)마다 지원하는 API나 헤더 파일이 다르다는 점을 고려해서 코드를 짜야 한다. (예를 들면 윈도우에서는 windows.h를 써야 하고, 리눅스에서는 unistd.h를 쓰는 식)

이럴 때 조건부 컴파일을 이용하면 코드 수정 없이 컴파일러가 알아서 해당 OS용 코드를 골라내게 할 수 있다.

1. 조건부 컴파일 개념

조건부 컴파일은 전처리기(Preprocessor) 단계에서 이루어진다.

컴파일러가 실제 기계어로 번역하기 전, #ifdef나 #if 같은 지시문을 보고 "이 부분은 포함하고, 저 부분은 버려라"라고 판단하는 것이다.

운영체제마다 컴파일러가 미리 정의해둔 예약 매크로(Predefined Macros)가 있는데, 이를 활용하면 현재 어떤 환경에서 컴파일 중인지 쉽게 알 수 있다.

 

2. 주요 운영체제별 예약 매크로

컴파일러는 현재 어떤 환경에서 코드를 빌드하고 있는지 알 수 있도록 미리 약속된 매크로를 제공한다.

가장 흔히 쓰이는 운영체제별 매크로는 다음과 같다.

대소문자까지 정확해야 하니 주의하자.

 

Windows 환경

  • _WIN32: 32비트와 64비트 Windows 모두에서 정의된다. Windows 환경임을 나타내는 가장 보편적인 기준이다.
  • _WIN64: 64비트 Windows 환경에서만 정의된다.
  • _MSC_VER: 마이크로소프트 비주얼 C++(MSVC) 컴파일러를 사용할 때 정의된다. 컴파일러 고유 기능을 쓸 때 유용하다.

Linux/Unix 환경

  • __linux__: 리눅스 시스템에서 정의된다.
  • __unix__: 유닉스 계열(Linux, BSD 등) 공통으로 사용될 때 정의된다.

Mac 환경

  •  __APPLE__ : Apple 플랫폼(주로 macOS/iOS 계열) 공통
  •  __MACH__ : Mach 기반(대부분 macOS에서 같이 정의)
운영체제 (OS) 예약 매크로
Windows (32/64bit 공통) _WIN32
Windows (64bit 전용) _WIN64
Linux __linux__
macOS (Apple 제품군) __APPLE__
Android __ANDROID__

 

 

3. 예시 코드: OS 맞춤형 메시지 출력하기

 

윈도우의 비트수(32/64bit)와 리눅스 환경을 구분하는 예제

// platform_ifdef.c
#include <stdio.h>

int main()
{
    // 1. 먼저 Windows 환경인지 확인
    #if defined(_WIN32) 
        // 2. Windows 내부에서 64비트 여부 판별
        #if defined(_WIN64)  
            printf("64bit MS Windows 환경이다.\n");
        #else  
            printf("32bit MS Windows 환경이다.\n");
        #endif
        
    // 3. Windows가 아니라면 (보통 Linux/Unix)
    #elif defined(__linux__)
        printf("Linux 환경이다.\n");
    #else
        printf("알 수 없는 운영체제다.\n");
    #endif

    printf("조건부 컴파일 지시문 이후의 공통 코드를 실행한다.\n");

    return 0;
}

 

 

  • #if defined(_WIN32): 64비트 윈도우에서도 _WIN32는 정의되어 있다. 이는 과거 32비트 API와의 호환성 및 관례 때문이다. 따라서 윈도우 전체를 묶을 때는 이 매크로를 먼저 사용한다.
  • 중첩 조건: 윈도우 안에서 다시 #if defined(_WIN64)를 사용해 비트수를 나눌 수 있다.
  • #elif와 #else: if-else 문과 구조가 비슷하지만, 조건에 맞지 않는 코드 블록은 컴파일 결과물(바이너리)에 아예 포함되지 않아 효율적이다.

 

 

4.  조건부 컴파일을 하는 이유

  • 이식성(Portability): 코드 하나로 윈도우, 리눅스, 맥 어디서든 컴파일할 수 있다. (크로스 플랫폼 개발)
  • 효율성: 실행 시점에 if 문으로 체크하는 게 아니라, 컴파일 시점에 필요한 코드만 남기기 때문에 실행 파일이 가볍고 빠르다.
  • 유지보수: OS별로 소스 파일을 따로 만들 필요가 없어 관리가 편하다.

💡  윈도우 64비트 환경에서는 _WIN32와 _WIN64가 모두 정의되어 있다. 따라서 64비트 전용 기능을 넣고 싶다면 #ifdef _WIN64를 먼저 체크하는 것이 좋다.