Một số giải thích. Cái đầu tiên là chung, cái thứ hai là dành riêng cho các macro tiền xử lý C với các tham số:
Kiểm soát lưu lượng
Tôi đã thấy điều này được sử dụng trong mã C đơn giản. Về cơ bản, đây là phiên bản an toàn hơn của goto, vì bạn có thể thoát ra khỏi nó và tất cả bộ nhớ được dọn sạch đúng cách.
Tại sao một cái gì đó gotogiống như là tốt? Vâng, nếu bạn có mã nơi khá nhiều mỗi dòng có thể trả về một lỗi, nhưng bạn cần phải phản ứng với tất cả chúng cùng một cách (ví dụ bằng cách bàn giao các lỗi để người gọi của bạn sau khi dọn dẹp), nó thường dễ đọc hơn để tránh if( error ) { /* cleanup and error string generation and return here */ }như nó tránh sự trùng lặp của mã dọn dẹp.
Tuy nhiên, trong C ++, bạn có ngoại lệ + RAII cho chính xác mục đích này, vì vậy tôi sẽ coi đó là phong cách mã hóa xấu.
Kiểm tra dấu chấm phẩy
Nếu bạn quên dấu chấm phẩy sau khi gọi macro giống như hàm, các đối số có thể co lại theo cách không mong muốn và biên dịch thành cú pháp hợp lệ. Tưởng tượng vĩ mô
#define PRINT_IF_DEBUGMODE_ON(msg) if( gDebugModeOn ) printf("foo");
Điều đó vô tình được gọi là
if( foo )
PRINT_IF_DEBUGMODE_ON("Hullo\n")
else
doSomethingElse();
Các "khác" sẽ được coi là liên quan đến việc gDebugModeOn, vì vậy khi foolà false, chính xác đảo ngược những gì đã được dự định sẽ xảy ra.
Cung cấp một phạm vi cho các biến tạm thời.
Vì do / while có dấu ngoặc nhọn, các biến tạm thời có phạm vi được xác định rõ ràng mà chúng không thể thoát.
Tránh các cảnh báo "có thể không mong muốn"
Một số macro chỉ được kích hoạt trong các bản dựng gỡ lỗi. Bạn định nghĩa chúng như:
#if DEBUG
#define DBG_PRINT_NUM(n) printf("%d\n",n);
#else
#define DBG_PRINT_NUM(n)
#endif
Bây giờ nếu bạn sử dụng điều này trong một bản phát hành bên trong một điều kiện, nó sẽ biên dịch thành
if( foo )
;
Nhiều trình biên dịch xem điều này giống như
if( foo );
Mà thường được viết vô tình. Vì vậy, bạn nhận được một cảnh báo. Do {} while (false) ẩn điều này khỏi trình biên dịch và được nó chấp nhận như một dấu hiệu cho thấy bạn thực sự không muốn làm gì ở đây.
Tránh bắt các dòng bởi các điều kiện
Macro từ ví dụ trước:
if( foo )
DBG_PRINT_NUM(42)
doSomething();
Bây giờ, trong một bản dựng gỡ lỗi, vì chúng ta cũng thường bao gồm dấu chấm phẩy, điều này biên dịch tốt. Tuy nhiên, trong bản phát hành, bản dựng này đột nhiên biến thành:
if( foo )
doSomething();
Hoặc được định dạng rõ ràng hơn
if( foo )
doSomething();
Đó không phải là tất cả những gì đã được dự định. Việc thêm một {...} while (false) xung quanh macro sẽ biến dấu chấm phẩy bị thiếu thành một lỗi biên dịch.
Điều đó có nghĩa gì với OP?
Nói chung, bạn muốn sử dụng các ngoại lệ trong C ++ để xử lý lỗi và các mẫu thay vì macro. Tuy nhiên, trong trường hợp rất hiếm khi bạn vẫn cần macro (ví dụ: khi tạo tên lớp bằng cách sử dụng dán mã thông báo) hoặc bị giới hạn ở đồng bằng C, đây là một mẫu hữu ích.