Bộ tiền xử lý C: Làm chủ #define, Macro và biên dịch có điều kiện
Khám phá sức mạnh của C Preprocessor: macro, conditional compilation, và các directive để tạo code linh hoạt và có thể tái sử dụng.
•19 tháng 10, 2025

Tóm tắt kiến thức
C Preprocessor là giai đoạn đầu tiên trong quá trình biên dịch, cho phép thao tác mã nguồn trước khi compile. Hiểu rõ preprocessor sẽ giúp bạn tạo ra code linh hoạt, có thể tái sử dụng và dễ bảo trì.
C Preprocessor là một công cụ mạnh mẽ trong ngôn ngữ lập trình C, thực hiện các thao tác trên mã nguồn trước khi trình biên dịch xử lý. Nó bao gồm các directive như #define, #include, #ifdef và nhiều tính năng khác giúp tạo ra mã linh hoạt, có thể tái sử dụng và dễ bảo trì.
Quảng cáo giúp chúng tôi duy trì trang web này
Tổng quan về C Preprocessor
Khái niệm Preprocessor
Preprocessor là giai đoạn đầu tiên trong quá trình biên dịch C. Nó xử lý các directive (chỉ thị) bắt đầu bằng dấu # trước khi trình biên dịch thực sự biên dịch mã.
Các directive chính
| Directive | Mô tả |
|---|---|
| #include | Bao gồm file header |
| #define | Định nghĩa macro |
| #undef | Hủy định nghĩa macro |
| Directive | Mô tả |
|---|---|
| #ifdef | Kiểm tra macro có được định nghĩa |
| #ifndef | Kiểm tra macro chưa được định nghĩa |
| #if | Điều kiện biên dịch |
| #else | Nhánh else cho điều kiện |
| #endif | Kết thúc điều kiện |
| #pragma | Chỉ thị đặc biệt cho trình biên dịch |
Tại sao Preprocessor quan trọng?
- Code reuse: Cho phép tái sử dụng code thông qua include
- Conditional compilation: Biên dịch khác nhau cho các platform
- Macro efficiency: Thay thế text để tối ưu hiệu suất
- Debugging: Có thể bật/tắt debug code
#include Directive
Cách sử dụng #include
#include <header_file.h> // Tìm trong thư mục hệ thống
#include "header_file.h" // Tìm trong thư mục hiện tạiVí dụ:
#include <stdio.h> // Thư viện chuẩn
#include <stdlib.h> // Thư viện chuẩn
#include "myheader.h" // Header file tự tạo
int main() {
printf("Hello, World!\n");
return 0;
}Tạo header file tùy chỉnh
myheader.h:
#ifndef MYHEADER_H
#define MYHEADER_H
#define PI 3.14159
#define MAX_SIZE 100
int add(int a, int b);
void printMessage(char *msg);
#endifmyheader.c:
#include "myheader.h"
#include <stdio.h>
int add(int a, int b) {
return a + b;
}
void printMessage(char *msg) {
printf("Message: %s\n", msg);
}#define Directive
Định nghĩa hằng số
#include <stdio.h>
#define PI 3.14159
#define MAX_STUDENTS 50
#define PROGRAM_NAME "Student Management System"
int main() {
printf("Chuong trinh: %s\n", PROGRAM_NAME);
printf("So sinh vien toi da: %d\n", MAX_STUDENTS);
printf("Gia tri PI: %.5f\n", PI);
return 0;
}Macro đơn giản
#include <stdio.h>
#define SQUARE(x) ((x) * (x))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
int main() {
int num = 5;
printf("Binh phuong cua %d: %d\n", num, SQUARE(num));
printf("Max cua 10 va 20: %d\n", MAX(10, 20));
printf("Min cua 10 va 20: %d\n", MIN(10, 20));
return 0;
}Macro phức tạp
#include <stdio.h>
#define SWAP(a, b) do { \
int temp = (a); \
(a) = (b); \
(b) = temp; \
} while(0)
#define DEBUG_PRINT(fmt, ...) \
printf("[DEBUG] " fmt "\n", ##__VA_ARGS__)
int main() {
int x = 10, y = 20;
printf("Truoc khi swap: x = %d, y = %d\n", x, y);
SWAP(x, y);
printf("Sau khi swap: x = %d, y = %d\n", x, y);
DEBUG_PRINT("Gia tri x: %d", x);
DEBUG_PRINT("Gia tri y: %d", y);
return 0;
}Conditional Compilation
#ifdef và #ifndef
#include <stdio.h>
#define DEBUG_MODE
int main() {
#ifdef DEBUG_MODE
printf("Che do debug dang bat\n");
printf("Thong tin chi tiet ve chuong trinh\n");
#endif
#ifndef RELEASE_MODE
printf("Chuong trinh dang trong che do phat trien\n");
#endif
return 0;
}#if với điều kiện
#include <stdio.h>
#define VERSION_MAJOR 2
#define VERSION_MINOR 1
int main() {
#if VERSION_MAJOR > 1
printf("Phien ban chinh: %d\n", VERSION_MAJOR);
#elif VERSION_MAJOR == 1
printf("Phien ban dau tien\n");
#else
printf("Phien ban phien ban thu nghiem\n");
#endif
#if VERSION_MINOR >= 1
printf("Phien ban phu: %d\n", VERSION_MINOR);
#endif
return 0;
}Ví dụ thực tế: Cross-platform code
#include <stdio.h>
// Giả sử các macro này được định nghĩa bởi trình biên dịch
// #define WINDOWS
// #define LINUX
// #define MACOS
void printOSInfo() {
#if defined(WINDOWS)
printf("He dieu hanh: Windows\n");
printf("Duong dan ngan cach: \\\n");
#elif defined(LINUX)
printf("He dieu hanh: Linux\n");
printf("Duong dan ngan cach: /\n");
#elif defined(MACOS)
printf("He dieu hanh: macOS\n");
printf("Duong dan ngan cach: /\n");
#else
printf("He dieu hanh: Khong xac dinh\n");
#endif
}
int main() {
printOSInfo();
return 0;
}Function-like Macros
Macro với tham số
#include <stdio.h>
#define ADD(a, b) ((a) + (b))
#define MULTIPLY(a, b) ((a) * (b))
#define POWER(base, exp) (exp == 0 ? 1 : base * POWER(base, exp - 1))
int main() {
int x = 5, y = 3;
printf("ADD(%d, %d) = %d\n", x, y, ADD(x, y));
printf("MULTIPLY(%d, %d) = %d\n", x, y, MULTIPLY(x, y));
return 0;
}Macro với nhiều tham số
#include <stdio.h>
#define PRINT_VALUES(a, b, c) \
printf("a = %d, b = %d, c = %d\n", (a), (b), (c))
#define CREATE_ARRAY(name, size, type) \
type name[size]
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
int main() {
int x = 10, y = 20, z = 30;
PRINT_VALUES(x, y, z);
CREATE_ARRAY(numbers, 5, int);
numbers[0] = 1;
numbers[1] = 2;
numbers[2] = 3;
numbers[3] = 4;
numbers[4] = 5;
printf("Kich thuoc mang: %zu\n", ARRAY_SIZE(numbers));
return 0;
}Macro với ## (Token Pasting)
#include <stdio.h>
#define DECLARE_VARIABLE(type, name) \
type var_##name
#define GET_VARIABLE(name) \
var_##name
#define CREATE_FUNCTION(name, type) \
type get_##name() { \
return var_##name; \
} \
void set_##name(type value) { \
var_##name = value; \
}
CREATE_FUNCTION(count, int)
CREATE_FUNCTION(price, float)
int main() {
DECLARE_VARIABLE(int, count);
DECLARE_VARIABLE(float, price);
set_count(100);
set_price(25.5);
printf("Count: %d\n", get_count());
printf("Price: %.2f\n", get_price());
return 0;
}Variadic Macros
Macro với số lượng tham số không xác định
#include <stdio.h>
#define PRINT(...) printf(__VA_ARGS__)
#define DEBUG_LOG(level, ...) \
printf("[%s] ", level); \
printf(__VA_ARGS__); \
printf("\n")
#define MAX_VARARGS(...) \
max_varargs_impl(__VA_ARGS__)
int max_varargs_impl(int count, ...) {
// Implementation for finding max
// This is simplified version
return count;
}
int main() {
PRINT("Xin chao %s, ban co %d diem!\n", "Anh", 85);
DEBUG_LOG("INFO", "Chuong trinh dang chay");
DEBUG_LOG("ERROR", "Co loi xay ra tai dong %d", 42);
DEBUG_LOG("WARNING", "Canh bao: %s", "Du lieu khong hop le");
return 0;
}Header Guards
Tránh include nhiều lần
math_utils.h:
#ifndef MATH_UTILS_H
#define MATH_UTILS_H
#define PI 3.14159
#define E 2.71828
int add(int a, int b);
int multiply(int a, int b);
double circle_area(double radius);
#endifmath_utils.c:
#include "math_utils.h"
int add(int a, int b) {
return a + b;
}
int multiply(int a, int b) {
return a * b;
}
double circle_area(double radius) {
return PI * radius * radius;
}main.c:
#include <stdio.h>
#include "math_utils.h" // Lần 1
#include "math_utils.h" // Lần 2 - sẽ bị bỏ qua
int main() {
printf("PI = %.5f\n", PI);
printf("Tong 5 + 3 = %d\n", add(5, 3));
printf("Dien tich hinh tron ban kinh 5: %.2f\n", circle_area(5.0));
return 0;
}#pragma Directive
Các #pragma phổ biến
#include <stdio.h>
// Bỏ qua cảnh báo
#pragma GCC diagnostic ignored "-Wunused-variable"
// Pack struct để tiết kiệm bộ nhớ
#pragma pack(push, 1)
struct PackedStruct {
char a;
int b;
char c;
};
#pragma pack(pop)
// Struct bình thường
struct NormalStruct {
char a;
int b;
char c;
};
int main() {
printf("Kich thuoc PackedStruct: %zu bytes\n", sizeof(struct PackedStruct));
printf("Kich thuoc NormalStruct: %zu bytes\n", sizeof(struct NormalStruct));
return 0;
}Macro Debugging
Macro để debug
#include <stdio.h>
#ifdef DEBUG
#define DBG_PRINT(fmt, ...) \
fprintf(stderr, "[DEBUG %s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#define DBG_ASSERT(condition) \
if (!(condition)) { \
fprintf(stderr, "[ASSERT FAILED %s:%d] %s\n", __FILE__, __LINE__, #condition); \
exit(1); \
}
#else
#define DBG_PRINT(fmt, ...)
#define DBG_ASSERT(condition)
#endif
void processArray(int *arr, int size) {
DBG_PRINT("Bat dau xu ly mang voi %d phan tu", size);
DBG_ASSERT(arr != NULL);
DBG_ASSERT(size > 0);
for (int i = 0; i < size; i++) {
DBG_PRINT("arr[%d] = %d", i, arr[i]);
arr[i] *= 2;
}
DBG_PRINT("Hoan thanh xu ly mang");
}
int main() {
int numbers[] = {1, 2, 3, 4, 5};
int size = sizeof(numbers) / sizeof(numbers[0]);
processArray(numbers, size);
printf("Mang sau khi xu ly: ");
for (int i = 0; i < size; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
return 0;
}Ví dụ thực tế: Configuration System
config.h:
#ifndef CONFIG_H
#define CONFIG_H
// Application configuration
#define APP_NAME "My Application"
#define APP_VERSION "1.0.0"
// Feature flags
#define ENABLE_LOGGING
#define ENABLE_DEBUG_MODE
// #define ENABLE_PRODUCTION_MODE
// Platform detection
#if defined(_WIN32)
#define PLATFORM_WINDOWS
#elif defined(__linux__)
#define PLATFORM_LINUX
#elif defined(__APPLE__)
#define PLATFORM_MACOS
#endif
// Conditional compilation based on features
#ifdef ENABLE_LOGGING
#define LOG_INFO(msg) printf("[INFO] %s\n", msg)
#define LOG_ERROR(msg) printf("[ERROR] %s\n", msg)
#else
#define LOG_INFO(msg)
#define LOG_ERROR(msg)
#endif
#ifdef ENABLE_DEBUG_MODE
#define DEBUG_PRINT(fmt, ...) printf("[DEBUG] " fmt "\n", ##__VA_ARGS__)
#else
#define DEBUG_PRINT(fmt, ...)
#endif
#endifmain.c:
#include <stdio.h>
#include "config.h"
void initializeApplication() {
LOG_INFO("Initializing application");
DEBUG_PRINT("Application name: %s", APP_NAME);
DEBUG_PRINT("Application version: %s", APP_VERSION);
#ifdef PLATFORM_WINDOWS
LOG_INFO("Running on Windows platform");
#elif defined(PLATFORM_LINUX)
LOG_INFO("Running on Linux platform");
#elif defined(PLATFORM_MACOS)
LOG_INFO("Running on macOS platform");
#else
LOG_ERROR("Unknown platform");
#endif
}
int main() {
initializeApplication();
#ifdef ENABLE_PRODUCTION_MODE
printf("Running in production mode\n");
#else
printf("Running in development mode\n");
#endif
return 0;
}Ví dụ thực hành
1. Tạo macro để đo thời gian thực thi
#include <stdio.h>
#include <time.h>
#define START_TIMER() clock_t start_time = clock()
#define END_TIMER() \
do { \
clock_t end_time = clock(); \
double cpu_time = ((double)(end_time - start_time)) / CLOCKS_PER_SEC; \
printf("Thoi gian thuc thi: %.6f giay\n", cpu_time); \
} while(0)
void bubbleSort(int arr[], int n) {
for (int i = 0; i < n-1; i++) {
for (int j = 0; j < n-i-1; j++) {
if (arr[j] > arr[j+1]) {
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
int main() {
int arr[1000];
// Khởi tạo mảng với giá trị ngẫu nhiên
for (int i = 0; i < 1000; i++) {
arr[i] = 1000 - i;
}
START_TIMER();
bubbleSort(arr, 1000);
END_TIMER();
return 0;
}2. Macro để tạo enum với string conversion
#include <stdio.h>
#define DECLARE_ENUM(name, ...) \
typedef enum { __VA_ARGS__ } name; \
const char* name##_strings[] = { #__VA_ARGS__ }; \
const char* name##_to_string(name value) { \
return name##_strings[value]; \
}
DECLARE_ENUM(Color, RED, GREEN, BLUE, YELLOW, PURPLE)
int main() {
Color myColor = BLUE;
printf("Mau cua toi: %s\n", Color_to_string(myColor));
return 0;
}Tổng kết
C Preprocessor là công cụ mạnh mẽ giúp tạo ra mã linh hoạt, có thể tái sử dụng và dễ bảo trì.
Lưu ý quan trọng về Preprocessor
- Macro side effects: Cẩn thận với side effects trong macro
- Operator precedence: Sử dụng dấu ngoặc đơn để tránh lỗi precedence
- Type safety: Macro không có type checking như function
- Debugging: Macro có thể khó debug hơn function
Best Practices
- Sử dụng header guards để tránh multiple inclusion
- Đặt tên macro bằng chữ hoa để phân biệt với variables
- Sử dụng do-while(0) cho macro multi-statement
- Tránh macro quá phức tạp, ưu tiên inline functions
Với những kiến thức này, bạn đã sẵn sàng để tạo ra các chương trình C linh hoạt, có thể tái sử dụng và dễ bảo trì!
Last updated on
Edit on GitHubCon trỏ trong C: Chìa khóa quản lý bộ nhớ và tối ưu hiệu suất
Khám phá sức mạnh của con trỏ trong C: quản lý bộ nhớ động, truyền tham chiếu, con trỏ hàm và các kỹ thuật tối ưu hiệu suất.
Thư viện chuẩn C: Khám phá các hàm hữu ích trong stdio.h, string.h, math.h
Khám phá sức mạnh của C Standard Library: stdio.h, stdlib.h, string.h, math.h và các hàm tiện ích quan trọng để viết code hiệu quả.