Gần đây khi bắt đầu đọc lại code C, tui thấy người ta thường wrap lại code macro trong một do {} while(0) loop. Ví dụ như:

#define LINK_MESSAGE_IMPL(p, first_msg, last_msg, num_msgs, where) do { \ *(p)->where.last = (first_msg); \ (p)->where.last = (last_msg); \ (p)->where.len += (num_msgs); \ } while(0)

Nếu bạn chưa biết macro (viết tắt của macroinstruction), nó là định nghĩa cách xuất ra một tập lệnh bằng cách thay thế một tập lệnh được viết sẵn. Giải thích một cách dân dã là dùng code để viết code. Trong C macros có thể được khai báo bằng cú pháp define .

Ví dụ ở đoạn code sau:

#define ANSI_COLOR_BLUE "\x1b[34m" #define ANSI_COLOR_RESET "\x1b[0m" #define LOG_DEBUG(message) printf(ANSI_COLOR_RED "line=%d %s" ANSI_COLOR_RESET, __LINE__, message) int main() { LOG_DEBUG("YOLO!"); return 0; }

Khi C compiler đọc đoạn code này, preprocessor sẽ triển khai những đoạn mã dùng macro LOG_DEBUG bằng định nghĩa của nó. Chương trình của bạn sau khi qua giai đoạn preprocess sẽ là:

int main() { printf("\x1b[34mline=%d %s\x1b[0m", __LINE__, "YOLO!"); return 0; }

Macro có thể giúp code của bạn súc tích hơn, dễ đọc hơn, dễ maintain hơn, và đôi khi performant hơn. Một ví dụ điển hình là bật tắt debug log giữa production/development environment.

Tuy nhiên vì macros chỉ rewrite lại code của bạn trong giai đoạn preprocessing, nếu không đủ kinh nghiệm hoặc bất cẩn, bạn có thể viết một chương trình bị lỗi logic.

Giả sử bạn viết một macro như sau:

#define PRINT_HELLO_WORLD_IN_DIFFERENT_LANGUAGES() \ printf("hello world"); \ printf("xin chào");

Và bắt đầu đưa nó vào sử dụng.

if (1 < 0) PRINT_HELLO_WORLD_IN_DIFFERENT_LANGUAGES();

Đoạn code có thể sẽ không thực hiện đúng ý đồ của chúng ta, bởi vì if chỉ nhận một single-line statement xếp sau nó, mà macro lại bao gồm hai statement.

if (1 < 0) printf("hello world"); printf("xin chào");

Vì không biết macro có được sử dụng như single-line statement hay không, nên để đảm bảo an toàn, các C developers thường bọc các dòng lệnh vào một đoạn do {} while(0) loop.

#define PRINT_HELLO_WORLD_IN_DIFFERENT_LANGUAGES() do {\ printf("hello world"); \ printf("xin chào"); \ } while(0)

Sẽ được triển khai thành:

if (1 < 0) do { printf("hello world"); printf("xin chào"); } while(0);

Thủ thuật này sẽ đảm bảo các macro bao gồm nhiều dòng lệnh có thể được sử dụng ở bất kì đâu, cả ở những nơi dùng nó như dòng lệnh đơn. Đồng thời vì điều kiện của vòng lặp là một hằng số, compiler sẽ không sinh ra mã nào để chạy vòng lặp, nên thủ thuật này không tạo ra overhead.