do {} while(0) loop
C
29
White

Cẩm Huỳnh viết ngày 06/07/2018

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.


Như thường lệ, bài viết được đăng lại từ Blog Quần Cam.

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Cẩm Huỳnh

47 bài viết.
463 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
69 5
image cover]imgcover] “Make it work, make it right, make it fast.” Bạn vừa viết xong một ứng dụng web :tada:. Mọi thứ chạy ổn. Code cũng đã được...
Cẩm Huỳnh viết 2 năm trước
69 5
White
48 26
Vừa rồi mình vừa tiết kiệm được $5 mỗi tháng sau khi migrate cái (Link) từ Digital Ocean sang Heroku Free Dyno. (Ảnh) Kết quả thật mĩ mãn vì hầu ...
Cẩm Huỳnh viết hơn 3 năm trước
48 26
White
46 9
(Ảnh) Vì sao lại là Bật Đèn? Ai từng đọc qua Tắt Đèn hẳn đã biết tác phẩm được kết thúc bằng tình huống: Buông tay, chị vội choàng dậy, mở cửa...
Cẩm Huỳnh viết hơn 3 năm trước
46 9
Bài viết liên quan
White
3 1
Chú ý: Bài viết này trình bày chủ yếu cho CentOS 64 bit, tuy nhiên ý tưởng có thể áp dụng cho các hệ điều hành khác. Cuối bài có ghi chú cho Ubunt...
Ngoc Dao viết hơn 4 năm trước
3 1
White
25 6
Gần đây tôi có dịp đụng vào CMake, nên có tìm hiểu một chút về nó. Hy vọng có ích cho anh em. Nó cung cấp tính năng sinh ra Makefile một cách hiệu...
Phùng Văn Tú viết 5 năm trước
25 6
White
9 1
Xử lí song song từ xa xưa cho đến gần đây là lãnh vực cao cấp hầu như chỉ dành cho các nhà khoa học. Có ít nhất 2 nguyên nhân: Xử lí song song đòi...
Ngoc Dao viết hơn 4 năm trước
9 1
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
47 bài viết.
463 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!