Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> C++

Cách hoạt động của Preprocessor (Bộ tiền xử lý) trong C/C++

Preprocessor (Bộ tiền xử lý) chạy trước compiler, xử lý các chỉ thị (directives) bắt đầu bằng #. Nó thực hiện: include file, định nghĩa macro, biên dịch điều kiện, thay thế văn bản.

Các chỉ thị chính

1. #include - Nhúng file


#include <stdio.h>      // File hệ thống (tim trong include path)
#include "myheader.h"   // File dự án (tim trong thư mục hiện tại trước)

2. #define - Định nghĩa macro


// Hằng số
#define PI 3.14159
#define MAX_SIZE 100

// Macro hàm (function-like)
#define SQUARE(x) ((x) * (x))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))

// Macro nhiều dòng (dùng \)
#define LOG(msg) \
    do { \
        fprintf(stderr, "[%s:%d] %s\n", __FILE__, __LINE__, msg); \
    } while(0)

Ví dụ sử dụng macro


#include <iostream>
#define PI 3.14159

int main() {
    std::cout << "PI = " << PI << std::endl;  // Thay thế văn bản: PI -> 3.14159
}

Kết quả

PI = 3.14159

3. Biên dịch điều kiện (Conditional Compilation)


// #ifdef / #ifndef - Kiểm tra macro đã định nghĩa
#ifdef DEBUG
    std::cerr << "Debug: x = " << x << std::endl;
#endif

#ifndef NULL
    #define NULL 0
#endif

// #if / #elif / #else / #endif - Điều kiện biểu thức
#if VERSION >= 2
    // Code phiên bản 2+
#elif VERSION == 1
    // Code phiên bản 1
#else
    #error "Phien ban khong ho tro"
#endif

// #if 0 - Comment khối code lớn
#if 0
    // Code này bị bỏ qua khi biên dịch
    old_function();
    deprecated_code();
#endif

Ví dụ hoàn chỉnh


#include <iostream>

#define DEBUG
#define MIN(a,b) (((a)<(b)) ? (a) : (b))

int main() {
    int i = 100, j = 30;
    
    #ifdef DEBUG
        std::cerr << "Trace: Vao main\n";
    #endif
    
    #if 0
        // Đoạn này không biên dịch
        std::cout << "Bi comment boi #if 0\n";
    #endif
    
    std::cout << "Min = " << MIN(i, j) << std::endl;
    
    #ifdef DEBUG
        std::cerr << "Trace: Ra main\n";
    #endif
}

Kết quả

Trace: Vao main
Min = 30
Trace: Ra main

4. #undef - Hủy định nghĩa macro


#define TEMP 100
// ... dùng TEMP ...
#undef TEMP  // Không còn dùng được TEMP

5. #line - Thay đổi dòng/file cho error message


#line 100 "custom_file.c"
int x;  // Lỗi sẽ báo: custom_file.c:100

6. #pragma - Chỉ thị compiler-specific


#pragma once           // Header guard hiện đại (hầu hết compiler hỗ trợ)
#pragma warning(disable: 4996)  // MSVC tắt warning
#pragma GCC optimize("O3")      // GCC bật tối ưu

Quy trình tiền xử lý

  1. Đọc file nguồn
  2. Xử lý #include (đệ quy nhúng file)
  3. Xử lý #define, #undef
  4. Xử lý #if, #ifdef, #else, #endif (loại bỏ code không biên dịch)
  5. Thay thế macro trong code
  6. Xuất file đã tiền xử lý (translation unit) cho compiler

Xem file sau tiền xử lý


# GCC/Clang:
gcc -E source.c -o source.i

# MSVC:
cl /E source.c

Lưu ý quan trọng

  • Preprocessor không hiểu cú pháp C/C++ — chỉ xử lý văn bản
  • Macro không tuân theo scope (phạm vi) của C++
  • Ưu tiên const/constexpr, inline function, template thay vì macro
  • #pragma once thay thế header guard truyền thống