+1

Rút gọn code bằng cách định nghĩa các Macro trong C++

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é.

Hi vọng kiến thức này hữu ích với bạn. Hẹn gặp lại 👋


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.