SỰ HỮU ÍCH CỦA MACRO (ĐẶC BIỆT LÀ TRONG LẬP TRÌNH THI ĐẤU)
Để định nghĩa một macro, chúng ta sẽ sử dụng từ khóa #define
Ví dụ:
#define PB push_back
#define MP make_pair
#define FI first
#define SE second
Giả sử ta có đoạn code:
v.push_back(make_pair(y1, x1));
v.push_back(make_pair(y2, x2));
int d = v[i].first + v[i].second;
thì sau khi áp dụng các macro ở trên, đoạn code sẽ trở nên ngắn gọn như sau:
v.PB(MP(y1, x1));
v.PB(MP(y2, x2));
int d = v[i].FI + v[i].SE;
Chắc hẳn khi code C++, nhiều bạn sẽ có thói quen sử dụng từ khóa endl
khi code để ngắt dòng và xuống một dòng mới.
Nhưng như ở video bài số 2 trong series video "Lên trình Thuật toán - Lập trình thi đấu 🏆" mình đã từng phân tích, sử dụng "\n"
sẽ chạy nhanh hơn endl
. Do đó, các bạn có thể khắc phục bằng cách tạo ra một macro là:
#define endl "\n"
Vậy là lúc này, bất cứ khi nào các bạn gõ endl
, thì trước khi biên dịch chương trình, nó sẽ đều được chuyển thành "\n"
để tối ưu hóa thời gian chạy.
Xem video phiên bản đầy đủ tại đây:
LƯU Ý KHI SỬ DỤNG MACRO
Mặc dù macro hay như vậy, nhưng đôi khi, nếu bạn không sử dụng đúng cách, thì có thể dẫn đến những lỗi rất khó phát hiện.
Ví dụ với một macro dùng để viết tắt cách tính bình phương của 1 số dưới đây:
#define SQ(a) a*a
với SQ
là viết tắt của Square of a number
Nếu ta chỉ truyền vào a
một số, ví dụ số 3
:
cout << SQ(3);
thì kết quả sẽ in ra đúng là 9
Nhưng khi truyền vào là 3+3
cout << SQ(3+3);
thì kết quả lại hiển thị ra là 15
, trong khi mong muốn của chúng ta là khi truyền vào 3+3
tức là 6
, thì sẽ in ra giá trị bình phương của nó là 6*6=36
Lý do là bởi vì khi truyền vào 3+3
, macro trên sẽ hiểu là chúng ta đang thực hiện phép toán a*a
là:
3+3*3+3
Khi này tuân theo quy tắc nhân chia trước, cộng trừ sau, nên chương trình sẽ thực hiện phép tính:
3 + (3 * 3) + 3 = 3 + 9 + 3 = 15
Để khắc phục lỗi này, chúng ta sẽ cần phải sử dụng thêm các cặp dấu ngoặc đơn trong macro. Ví dụ:
#define SQ(a) (a)*(a)
Khi đó nếu chạy lại chương trình, chúng ta sẽ thấy kết quả hiện ra đúng là 36
Bởi vì lúc này, macro sẽ hiểu đoạn code của chúng ta là:
(3+3) * (3+3) = 6 * 6 = 36
ĐỊNH NGHĨA MACRO CÓ KÈM CÁC THAM SỐ
Một macro cũng có thể có các tham số (parameters) để giúp các đoạn code dài như vòng lặp for trở nên ngắn gọn hơn. Ví dụ ta có một vòng lặp for như sau:
for (int i = 1; i <= n; i++) { cout << i << endl;
}
Chúng ta có thể định nghĩa 1 macro để viết tắt cho hàm for
này. Ví dụ:
#define FOR(i,a,b) for (int i = (a); i <= (b); i++)
Khi đó, những nơi nào có sử dụng hàm for sẽ chỉ còn ngắn gọn như sau:
FOR(i,1,n) { cout << i << endl;
}
Như các bạn thấy, mình có thói quen đặt tên viết tắt trong macro bằng cách sử dụng CÁC KÝ TỰ VIẾT HOA, điều này sẽ giúp mình dễ dàng nhận biết được các macro khi đọc lại code.
Và đây cũng là thói quen định nghĩa các hằng số (hay còn gọi là constant) khi mình code ở các dự án phần mềm.
Các bạn cũng có thể tham khảo và áp dụng cách code này nếu thấy phù hợp nhé.