Đối với tôi do{...}while(0)
là tốt. Nếu bạn không muốn xem do{...}while(0)
, bạn có thể xác định từ khóa thay thế cho chúng.
Thí dụ:
//--------SomeUtilities.hpp---------
#define BEGIN_TEST do{
#define END_TEST }while(0);
//--------SomeSourceFile.cpp--------
BEGIN_TEST
if(!condition1) break;
if(!condition2) break;
if(!condition3) break;
if(!condition4) break;
if(!condition5) break;
//processing code here
END_TEST
Tôi nghĩ rằng trình biên dịch sẽ loại bỏ các while(0)
điều kiện không cần thiết trongdo{...}while(0)
trong phiên bản nhị phân và chuyển đổi các ngắt thành bước nhảy vô điều kiện. Bạn có thể kiểm tra phiên bản ngôn ngữ lắp ráp để đảm bảo.
Việc sử dụng goto
cũng tạo ra mã sạch hơn và nó đơn giản với logic điều kiện-sau đó nhảy. Bạn có thể làm như sau:
{
if(!condition1) goto end_blahblah;
if(!condition2) goto end_blahblah;
if(!condition3) goto end_blahblah;
if(!condition4) goto end_blahblah;
if(!condition5) goto end_blahblah;
//processing code here
}end_blah_blah:; //use appropriate label here to describe...
// ...the whole code inside the block.
Lưu ý nhãn được đặt sau khi đóng }
. Đây là một vấn đề có thể tránh goto
được là việc vô tình đặt mã ở giữa vì bạn không nhìn thấy nhãn. Bây giờ giống như do{...}while(0)
không có mã điều kiện.
Để làm cho mã này sạch hơn và dễ hiểu hơn, bạn có thể làm điều này:
//--------SomeUtilities.hpp---------
#define BEGIN_TEST {
#define END_TEST(_test_label_) }_test_label_:;
#define FAILED(_test_label_) goto _test_label_
//--------SomeSourceFile.cpp--------
BEGIN_TEST
if(!condition1) FAILED(NormalizeData);
if(!condition2) FAILED(NormalizeData);
if(!condition3) FAILED(NormalizeData);
if(!condition4) FAILED(NormalizeData);
if(!condition5) FAILED(NormalizeData);
END_TEST(NormalizeData)
Với điều này, bạn có thể thực hiện các khối lồng nhau và chỉ định nơi bạn muốn thoát / nhảy ra.
//--------SomeUtilities.hpp---------
#define BEGIN_TEST {
#define END_TEST(_test_label_) }_test_label_:;
#define FAILED(_test_label_) goto _test_label_
//--------SomeSourceFile.cpp--------
BEGIN_TEST
if(!condition1) FAILED(NormalizeData);
if(!condition2) FAILED(NormalizeData);
BEGIN_TEST
if(!conditionAA) FAILED(DecryptBlah);
if(!conditionBB) FAILED(NormalizeData); //Jump out to the outmost block
if(!conditionCC) FAILED(DecryptBlah);
// --We can now decrypt and do other stuffs.
END_TEST(DecryptBlah)
if(!condition3) FAILED(NormalizeData);
if(!condition4) FAILED(NormalizeData);
// --other code here
BEGIN_TEST
if(!conditionA) FAILED(TrimSpaces);
if(!conditionB) FAILED(TrimSpaces);
if(!conditionC) FAILED(NormalizeData); //Jump out to the outmost block
if(!conditionD) FAILED(TrimSpaces);
// --We can now trim completely or do other stuffs.
END_TEST(TrimSpaces)
// --Other code here...
if(!condition5) FAILED(NormalizeData);
//Ok, we got here. We can now process what we need to process.
END_TEST(NormalizeData)
Mã spaghetti không phải là lỗi của goto
, đó là lỗi của lập trình viên. Bạn vẫn có thể sản xuất mã spaghetti mà không cần sử dụng goto
.