C/C++ Preprocessor (Phần 2) - Macro
C
27
C++
27
C/C++
5
White

Võ Phi Hùng viết ngày 30/03/2017

Khái niệm macro và ví dụ

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). Đây là để làm ví dụ thôi chứ mình không có khuyến khích ai thực hành đoạn code trên cả.

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);
float 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ử ##

Cái này làm mình gặp chút khó khăn trong lúc viết vì nó xung đột với kí pháp của markdown. Toán tử ## có tác dụng nối 2 token lại với nhau (mình gặp rắc rối với việt hoá từ token này, hy vọng các bạn không quá khó hiểu), 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. Bài tiếp theo mình sẽ trình bày về các nguy cơ gặp phải về dùng macro và tại sao nên tránh macro khi có thể.

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Võ Phi Hùng

6 bài viết.
32 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
13 5
Bài này được mình dịch lại từ bài gốc ở đây. http://www.joelonsoftware.com/articles/fog0000000069.html Của tác giả Joel Spolsky thuộc công ty Netsc...
Võ Phi Hùng viết hơn 2 năm trước
13 5
White
9 2
Khi làm quen với C hoặc C++ chắc bạn sẽ rất quen với mấy dòng kiểu như sau ở đầu và cuối mỗi file .h c++ ifndef _file_name_h define _file_name_h ...
Võ Phi Hùng viết hơn 2 năm trước
9 2
White
8 2
Từ khoá virtual có một số đặc tính khá thú vị mà mình muốn chia sẻ với các đồng chí ngày hôm nay. Bài viết có vẻ hơi dài hơn mức cần thiết nhưng đừ...
Võ Phi Hùng viết hơn 2 năm trước
8 2
Bài viết liên quan
White
3 1
Chú ý: Bài viết này trình bày chủ yếu cho CentOS 64 bit, tuy nhiên ý tưởng có thể áp dụng cho các hệ điều hành khác. Cuối bài có ghi chú cho Ubunt...
Ngoc Dao viết gần 2 năm trước
3 1
White
17 2
Gần đây tôi có dịp đụng vào CMake, nên có tìm hiểu một chút về nó. Hy vọng có ích cho anh em. Nó cung cấp tính năng sinh ra Makefile một cách hiệu...
Phùng Văn Tú viết hơn 2 năm trước
17 2
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
6 bài viết.
32 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!