2013-04-24 33 views
5

Tôi đang tìm kiếm macro tương tự với cấu trúc có. Việc sử dụng nên được một cái gì đó như:"có" macro trong C

with (lock(&x), unlock(&x)) { 
    ... 
} 

Nó có thể có ích cho một số mục đích khác.

tôi đến với macro này:

#define __with(_onenter, _onexit, v) \ 
    for (int __with_uniq##v=1; __with_uniq##v > 0;)\ 
     for (_onenter; __with_uniq##v > 0; _onexit) \ 
      while (__with_uniq##v-- > 0) 

#define _with(x, y, z) __with(x, y, z) 
#define with(_onenter, _onexit) _with(_onenter, _onexit, __COUNTER__) 

Nó có 3 vòng lồng nhau vì nó nên:

  1. Initialize loop truy cập (C99 chỉ, tất nhiên)
  2. Có thể khởi tạo _onenter biến (chẳng hạn như with (int fd=open(..), close(fd)))
  3. Cho phép break bên trong khối mã. (continue cũng được phép. Và macro có thể được điều chỉnh thành assert() nó ra)

Tôi đã sử dụng mã này trên hệ điều hành XV6 và có vẻ khá hữu ích.

Câu hỏi của tôi là - các sự cố tồi tệ nhất với macro như vậy là gì? Tôi có nghĩa là, bên cạnh việc sử dụng chỉ của một vĩ mô C (đặc biệt là một trong đó thực hiện mới kiểm soát dòng chảy xây dựng).

Cho đến nay đã phát hiện ra những nhược điểm/vấn đề:

  1. Không hỗ trợ return hoặc goto (nhưng nó có thể tiết kiệm một số goto s trong mã kernel)
  2. Không hỗ trợ cho các lỗi (như fd < 0). Tôi nghĩ cái này có thể sửa được.
  3. gnu89/c99 trở lên chỉ (bộ đếm vòng lặp. Không cần sử dụng biến số duy nhất)
  4. Hơi kém hiệu quả hơn so với khóa mở khóa đơn giản. Tôi tin nó không đáng kể.

Có sự cố nào khác không? Có cách nào tốt hơn để thực hiện cấu trúc tương tự trong C?

Trả lời

6

Macro đó làm tôi sợ. Tôi thích số traditional approach using gotos.

Cách tiếp cận đó là nguyên thủy, nhưng hầu hết các lập trình viên C đều quen thuộc với mẫu và nếu không, họ có thể hiểu nó bằng cách đọc mã cục bộ. Không có hành vi ẩn. Kết quả là, nó khá đáng tin cậy.

Macro của bạn là thông minh, nhưng nó sẽ là mới đối với hầu hết mọi người và nó đi kèm với gotchas ẩn. Những người đóng góp mới sẽ phải là các quy tắc suy nghĩ như "không return hoặc goto ngoài khối" và "break sẽ thoát ra khỏi khối đó, không nằm ngoài vòng lặp xung quanh". Tôi sợ những sai lầm sẽ là phổ biến.

Số dư sẽ thay đổi nếu bạn có thể thêm cảnh báo về việc lạm dụng cấu trúc này cho trình biên dịch. With clang, có vẻ như là một lựa chọn. Trong trường hợp này, việc lạm dụng sẽ được phát hiện và mã của bạn sẽ vẫn được chuyển sang các trình biên dịch khác.

Nếu bạn sẵn sàng giới hạn bản thân với GCC và Clang, bạn có thể sử dụng thuộc tính cleanup.Điều đó sẽ làm cho ví dụ của bạn trông giống như sau:

lock_t x = NULL __attribute__((cleanup(unlock))); 
lock(&x); 

unlock sẽ được gọi với con trỏ đến biến khi nằm ngoài phạm vi. Điều này được tích hợp với các tính năng ngôn ngữ khác như returngoto và thậm chí có ngoại lệ trong các dự án C/C++ hỗn hợp.

+0

Ồ. phản ứng cuối cùng ... Cảm ơn bạn, tôi không biết về 'cleanup' - âm thanh hữu ích. Liệu macro có vấn đề cụ thể hơn, bên cạnh sự đáng sợ của nó? – Elazar

+1

Việc thiếu sự hỗ trợ cho 'return' có vẻ như một bộ ngắt thỏa thuận, trừ khi bạn đang làm việc với một tiêu chuẩn mã hóa nghiêm ngặt đối với các câu lệnh' return' ở giữa các hàm. Một 'return' trong một khối' with' sẽ trông không dễ thấy nhưng sẽ tàn phá vào thời gian chạy. – pdw

+0

Tôi hiểu và đồng ý rằng 'return' là một vấn đề lớn (vì vậy' cleanup' tốt hơn nhiều). Nhưng không 'goto' yêu cầu tiêu chuẩn mã hóa nghiêm ngặt như nhau? Những ưu điểm của goto, về mặt này là gì? – Elazar