C/C++ Preprocessor

C/C++ Preprocessor

Khái niệm macro

Macro - một cái tên nghe khá hổ báo, được dùng để chỉ những hàm được viết ở phần Preprocessor, thay vì đặt nó vào trong phần thực thi của file nguồn. Ngoài ra khi nói đến macro có 1 nghĩa khác nữa, ám chỉ đến tất cả những phần định nghĩa được viết trong phần Preprocessor. Trong bài viết này thì mình dùng macro với cách dùng đầu tiên. Ví dụ đơn giản về macro như sau:

#define PRINT_HELLO_WORLD printf("Hello world")

Macro trên không tham số, chỉ một dòng duy nhất, và compiler sẽ đơn giản là thay thế bất cứ chỗ nào có PRINT_HELLO_WORLD ở trong source code bằng câu lệnh print("Hello world).

Sau khi không gặp bất cứ vấn đề gì với đồng chí PRINT_HELLO_WORLD ở trên. Chúng ta xét tiếp 1 ví dụ về macro có tham số.

#define ADD_TWO_NUMBER(x, y) x + y

Và dùng nó ở đoạn code dưới đây

int z_1 = ADD_TWO_NUMBER(10, 3);
foat z_2 = ADD_TWO_NUMBER(10.1, 3.7);

Macro trên sẽ khớp với bất cứ đoạn code nào có dạng ADD_TWO_NUMBER(param_1, param_2) và thay nó bằng param_1 + param_2 và nó không (thể) biết param_1param_2 là gì, có thể là biểu thức có thể là biến, có thể là string mà cũng có thể là int. Đó cũng chính là điểm mạnh và cũng là điểm yếu của macro, bạn có thể dùng hàm trên để cộng 2 biến kiểu int hay float như trên. Tuy nhiên nó cũng tiềm tàng nhiều mối nguy hiểm mà mình sẽ đề cập ở 1 bài khác.

Các thao tác với macro

Toán tử ##

Toán tử ## có tác dụng nối 2 token lại với nhau, tương tự như các bạn nối string thôi, không có gì phức tạp cả. Ví dụ:

#define float_type fl##oat
...
float_type a = 10.0;

Về ứng dụng thực tế của ## thì thường được dùng trong để đặt tên cho biến, hàm hoặc class. Ví dụ như bạn muốn khai báo 3 biến là normal_bike_price, premium_bike_price, low_bike_price thì thay vì khai báo thủ công, bạn có thể dùng macro như sau.

#define DECLARE_VARIABLES(type, name) type normal_##name, premium_##name, low_##name
...
DECLARE_VARIABLES(int, bike_price);

Câu lệnh trên sẽ được chuyển thành đoạn code sau khi chạy chương trình:

int normal_bike_price, premium_bike_price, low_bike_price;

Macro nhiều dòng (multi line macro)

Để khai báo một function (tầm cỡ vài chục câu lệnh) thì ý tưởng viết tất cả chúng vào tất cả 1 dòng là không sáng sủa tí nào. Và để xuống dòng trong macro thì bạn sẽ dùng ký tự *\*. Như trong ví dụ sau đây chúng ta sẽ sửa lại đoạn code trên 1 chút để nó thành 1 macro có nhiều dòng nhằm cho thấy tác dụng của kí tự *\*.

#define DECLARE_VARIABLES(type, name) type normal_##name;\
type premium_##name;\
type low##_name;

Toán tử #

# dùng để chuyển 1 token nào đó thành chuỗi. Ví dụ như sau.

#define print_variable_name_and_value(x) printf(#x " value is: %d", x)
...
int x = 10;
print_variable_name_and_value(x);

câu lệnh print_variable_name_and_value(x); sẽ được chuyển thành printf("x" " value is: %d", x); và kết quả câu lệnh trên sẽ là

x value is: 10

Kết luận

Trên đây là các kiến thức cơ bản về macro nhưng từng này là tương đối đủ để các bạn đọc hiểu Preprocessor code của một số các thư viện C++ hiện tại.

Macro hữu dụng nhưng lại có rất nhiều nguy cơ tiềm ẩn, tại sao nên tránh sử dụng macro khi có thể sẽ được trình bày ở bài khác.

Từ Kipalog