Bộ tiền xử lý trong C không phải là một phần của trình biên dịch mà là một bước riêng biệt trong quá trình biên dịch. Nói một cách đơn giản, bộ tiền xử lý C là một công cụ thay thế văn bản và nó chỉ thị trên trình biên dịch khi cần thực hiện trước khi xử lý.
Tất cả các lệnh tiền xử lý bắt đầu bằng một biểu tượng ký tự [#], là ký tự đầu tiên không trống và dễ đọc, một chỉ thị tiền xử lý nên bắt đầu trong cột đầu tiên. Phần sau liệt kê tất cả các chỉ thị quan trọng trong tiền xử lý:
Directive
Miêu tả
define
Thay thể cho bộ tiền xử lý macro
include
Chèn một header đặc biệt từ file khác
undef
Không định nghĩa một macro tiền xử lý
ifdef
Trả về giá trị true nếu macro này được định nghĩa
ifndef
Trả về giá trị true nếu macro này không được định nghĩa
if
Kiểm tra nếu điều kiện biên dịch là đúng
else
Phần thay thế cho
if
elif
else một
if trong một lệnh
endif
Kết thúc điều kiện tiền xử lý
error
In thông báo lỗi trên stderr
pragma
Thông báo các lệnh đặc biệt đến bộ biên dịch, sử dụng một phương thức được tiêu chuẩn hóa
1. Ví dụ bộ tiền xử lý
Phân tích các ví dụ sau để hiểu các chỉ thị khác nhau:
define MAX_ARRAY_LENGTH 20
Chỉ thị này yêu cầu CPP thay thế các trường hợp MAX_ARRAY_LENGTH bằng 20. Sử dụng
define cho các hằng số để tăng khả năng đọc.
include
include "myheader.h"
Các chỉ thị này yêu cầu CPP lấy stdio.h từ System Libraries và thêm văn bản vào tệp nguồn hiện tại. Dòng tiếp theo yêu cầu CPP lấy myheader.h từ thư mục cục bộ và thêm nội dung vào tệp nguồn hiện tại.
undef FILE_SIZE
define FILE_SIZE 42
Nó yêu cầu CPP xác định FILE_SIZE hiện tại và xác định nó là 42.
ifndef MESSAGE
define MESSAGE "You wish!"
endif
Nó báo cho CPP chỉ định MESSAGE nếu MESSAGE chưa được định nghĩa.
ifdef DEBUG
/* Your debugging statements here */
endif
Nó báo cho CPP xử lý các câu lệnh kèm theo nếu DEBUG được định nghĩa. Điều này rất hữu ích nếu bạn chuyển cờ -DDEBUG tới trình biên dịch gcc tại thời điểm biên dịch. Điều này sẽ xác định DEBUG, vì vậy bạn có thể bật và tắt gỡ lỗi khi đang di chuyển trong khi biên dịch.
2. Các Macro được định nghĩa trước trong C
ANSI C định nghĩa một số macro, mặc dù mỗi cái đều có sẵn để sử dụng trong lập trình, nhưng các macro được xác định trước nên không thể sửa đổi trực tiếp.
Macro
Mô tả chi tiết
__DATE__
Ngày hiện tại dưới dạng ký tự theo nghĩa đen trong định dạng "MMM DD YYYY".
__TIME__
Thời gian hiện tại dưới dạng ký tự theo nghĩa "HH: MM: SS".
__FILE__
Điều này chứa tên tệp hiện tại dưới dạng chuỗi ký tự.
__LINE__
Điều này chứa số dòng hiện tại dưới dạng hằng số thập phân.
__STDC__
Được định nghĩa là 1 khi trình biên dịch tuân thủ tiêu chuẩn ANSI.
Hãy thử ví dụ sau:
include
int main[] {
printf["File :%s\n", __FILE__ ];
printf["Date :%s\n", __DATE__ ];
printf["Time :%s\n", __TIME__ ];
printf["Line :%d\n", __LINE__ ];
printf["ANSI :%d\n", __STDC__ ];
}
Khi đoạn mã trên trong tệp test.c được biên dịch và thực thi, nó tạo ra kết quả sau:
File :test.c
Date :Jun 2 2012
Time :03:36:24
Line :8
ANSI :1
3. Toán tử tiền xử lý trong C
Bộ tiền xử lý C cung cấp các toán tử sau để giúp tạo macro:
- Toán tử Macro Continuation [\]
Macro thường được giới hạn trong một dòng, toán tử tiếp tục macro [\] được sử dụng để tiếp tục macro quá dài cho một dòng. Ví dụ:
define message_for[a, b] \
printf[
a " and "
b ": We love you!\n"]
- Toán tử Stringize [#]
Toán tử stringize hoặc number-sign ['#'], khi được sử dụng trong định nghĩa macro, chuyển đổi một tham số macro thành hằng số chuỗi. Toán tử này chỉ có thể được sử dụng trong một macro có một đối số hoặc danh sách tham số được chỉ định. Ví dụ:
include
define message_for[a, b] \
printf[
a " and "
b ": We love you!\n"]
int main[void] {
message_for[Carole, Debra];
return 0;
}
Khi mã trên được biên dịch và thực hiện, nó tạo ra kết quả sau:
Carole and Debra: We love you!
- Toán tử Token Pasting [##]
Toán tử dán mã thông báo [##] trong một định nghĩa macro kết hợp hai đối số. Nó cho phép hai thẻ riêng biệt trong định nghĩa macro được kết hợp thành một mã thông báo duy nhất. Ví dụ:
include
define tokenpaster[n] printf ["token"
n " = %d", token
n]
int main[void] {
int token34 = 40;
tokenpaster[34];
return 0;
}
Khi mã trên được biên dịch và thực hiện, nó tạo ra kết quả sau:
token34 = 40
Nó xảy ra như vậy bởi vì ví dụ này dẫn đến kết quả đầu ra thực tế sau đây từ bộ tiền xử lý:
printf ["token34 = %d", token34];
Ví dụ này cho thấy việc nối mã thông báo ## n vào mã token34 và ở đây chúng tôi đã sử dụng cả chuỗi và dán mã thông báo.
- Toán tử Defined []
Toán tử được xác định sử dụng trong các biểu thức hằng số để xác định nếu một định danh được định nghĩa bằng cách sử dụng
define. Nếu định danh được chỉ định được xác định, giá trị là đúng [khác không]. Nếu ký hiệu không được xác định, giá trị là false [số không]. Toán tử được định nghĩa được quy định như sau:
include
if !defined [MESSAGE]
define MESSAGE "You wish!"
endif
int main[void] {
printf["Here is the message: %s\n", MESSAGE];
return 0;
}
Khi mã trên được biên dịch và thực hiện, nó tạo ra kết quả sau:
Here is the message: You wish!
- Tham số Macro
Một trong những chức năng mạnh mẽ của CPP là khả năng mô phỏng các chức năng sử dụng các macro tham số hóa. Ví dụ:
int square[int x] {
return x * x;
}
Chúng ta có thể viết lại đoạn mã trên bằng cách sử dụng macro như sau:
define square[x] [[x] * [x]]
Các macro có đối số phải được xác định bằng cách sử dụng lệnh