2011-10-19 45 views
11

thời gian gần đây tôi thấy GCC này vĩ mô:Làm thế nào để `({...})` trả về một giá trị?

#define max(a,b) \ 
    ({ typeof (a) _a = (a); \ 
     typeof (b) _b = (b); \ 
    _a > _b ? _a : _b; }) 

Tôi đã không nhận ra trước khi tôi thấy mã này, rằng một khối mã {...} bằng cách nào đó có thể trở lại giá trị trong C.
1) Ông có thể cho tôi một gợi ý làm thế nào điều này hoạt động?

Mặc dù, tôi thường đã có thể đạt được kết quả tương tự bằng cách lợi dụng các nhà điều hành dấu phẩy:

#define max(a,b) \ 
    (typeof (a) _a = (a), \ 
    typeof (b) _b = (b), \ 
    (_a > _b ? _a : _b)) 

hoặc nếu nó chỉ cho tác dụng phụ tôi sẽ sử dụng do { ... } while(0)

2) gì là cách ưa thích để làm điều này?

+1

có thể trở thành câu hỏi được bảo vệ! nhiều C (và C++, tôi tin) các lập trình viên không biết rằng '({...})' là một phần mở rộng GCC và không phải là một phần của ngôn ngữ C. IMHO. – Jack

Trả lời

9

Cấu trúc ({ ... }) là phần mở rộng gcc.

Vì vậy, là nhà điều hành typeof.

Một vĩ mô MAX (lưu ý việc sử dụng thông thường của tất cả các-mũ) là đủ dễ dàng để viết:

#define MAX(a, b) ((a) > (b) ? (a) : (b)) 

Nó đánh giá một trong những đối số của nó nhiều hơn một lần, vì vậy bạn không nên gọi nó như là, ví dụ: MAX(x++, y--). Việc sử dụng tất cả các mũ phục vụ để nhắc nhở người dùng rằng đó là một macro, không phải là một chức năng, và phải cẩn thận về các đối số với các tác dụng phụ.

Hoặc bạn có thể viết hàm (có thể là hàm nội tuyến) cho từng loại.

+2

+1 Wow: - |, thực sự không biết về '({...})'. Họ nên đặt nó hoàn toàn bằng ngôn ngữ. – cnicutar

+2

Cảm ơn bạn đã liên kết ['({...})'] (http://gcc.gnu.org/onlinedocs/gcc-4.6.1/gcc/Statement-Exprs.html#Statement-Exprs)! Nó luôn luôn khó với google chỉ với dấu chấm câu. – Halst

10

Đây là phần mở rộng GCC. Các nhà điều hành dấu phẩy không hoạt động:

// C89, doesn't work... 
#define max(a,b) \ 
    (typeof (a) _a = (a), \ 
    typeof (b) _b = (b), \ 
    (_a > _b ? _a : _b)) 

điều hành các dấu phẩy chỉ hoạt động với các biểu thức, và typeof(a) _a = (a); là một tuyên bố, không phải là một biểu hiện. Nó không thực sự có thể viết một macro tương đương mà không có phần mở rộng GCC hoặc C11, trong đó có _Generic. Lưu ý rằng typeof là một phần mở rộng GCC, do đó bạn không đạt được bất kỳ tính di động nào bằng cách loại bỏ ({...}) trừ khi bạn loại bỏ typeof.

Đây là phiên bản C11, lưu ý mức độ chi tiết bằng cách so sánh (và nó chỉ xử lý hai loại!). C11 thậm chí không được hỗ trợ nào, chúc may mắn cố gắng tìm một trình biên dịch để kiểm tra này:

// C11 
static inline int maxi(int x, int y) { return x > y ? x : y; } 
static inline long maxl(long x, long y) { return x > y ? x : y; } 
#define max(x, y) _Generic((x), \ 
    long: maxl(x,y), \ 
    int:_Generic((y), \ 
     int: maxi(x,y), \ 
     long: maxl(x,y))) 

Trong di C99, bạn có thể viết một hàm vĩ mô hoặc inline mà đạt được tác dụng tương tự, ngoại trừ nó sẽ chỉ làm việc cho một loại cho mỗi macro.

// C99 
static inline int maxi(int x, int y) { return x > y ? x : y; } 

Trong C89/C90, tôi không thể nghĩ ra cách nào để viết macro trong một cách như vậy mà nó sẽ không đánh giá x hoặc y hai lần.

+7

Xin đừng viết câu trả lời mà không nói gì cả. Chỉ cần bide thời gian của bạn và viết một câu trả lời tốt. Nó sẽ nhận được rất nhiều upvotes nếu nó là tốt. Không cần phải cố gắng và yêu cầu bồi thường câu hỏi như của riêng bạn. –

+0

Xin lỗi, tôi đang ở trên một thiết bị đầu cuối không quen thuộc và tôi đang cố lưu các bản nháp để không bị mất những gì tôi viết. Không thực sự cố gắng "tuyên bố câu hỏi như của riêng tôi." –

+1

Ok, +1 ngay bây giờ, câu trả lời tuyệt vời –

Các vấn đề liên quan