2011-08-31 21 views
7
FUNC(param); 

Khi paramchar *, gửi đến func_string.Làm thế nào để thực hiện một macro chung trong C?

khi nó int, công văn đến func_int

Tôi nghĩ rằng có thể có một giải pháp này, như các loại biến được biết tại thời gian biên dịch ..

+0

Ngay cả khi điều này là có thể, nó sẽ là một cách hợp lý. C không được thiết kế cho nó. Sử dụng cấu trúc và công đoàn, bạn thậm chí có thể nhận được công văn thời gian chạy theo cách đó. –

Trả lời

10

loại Variable được biết là trình biên dịch, nhưng không phải để bộ tiền xử lý (xem mã đơn giản là văn bản không được cấu trúc một luồng mã thông báo và chỉ thực hiện các thao tác thay thế đơn giản trên đó). Vì vậy, tôi sợ bạn không thể đạt được điều này với các macro C.

Trong C++, họ đã phát minh ra các mẫu để giải quyết các vấn đề đó (và hơn thế nữa).

+0

Có công việc nào trong ** C ** không? – lexer

+2

Đây là một kết luận sai lầm. Bộ tiền xử lý không cần biết các kiểu đối số, nếu bạn có thể sắp xếp mở rộng macro để trình biên dịch * có thể thực hiện phân tích. Xem câu trả lời của arnaud576875 làm thế nào để giải quyết điều này cho trình biên dịch gnu. Ngoài ra, bộ tiền xử lý không thấy mã dưới dạng văn bản không có cấu trúc, nhưng dưới dạng luồng * mã thông báo *, đây là một sự khác biệt quan trọng. –

1

Bạn không thể thực hiện việc này bằng macro. Giá trị của Macro được thay thế tại thời gian biên dịch và không được intepreted. Họ chỉ là thay thế.

11

Điều này sẽ có thể với C1X nhưng không theo tiêu chuẩn hiện tại.

Nó sẽ giống như thế này:

#define cbrt(X) _Generic((X), long double: cbrtl, \ 
          default: cbrt, \ 
          float: cbrtf)(X) 
+0

Khi câu hỏi này bật lên đầu tiên trên google: điều này bây giờ có thể sử dụng C11 http://en.cppreference.com/w/c/language/generic –

4

Không có khả năng để chạy các loại thời gian check in C89/ANSI C, nhưng có một phần mở rộng cho gcc cho phép nó. typeof hoặc một cái gì đó dọc theo những dòng nếu tôi nhớ. Tôi đã thấy nó trong hạt nhân Linux một lần.

Trong kernel.h:

#define min(x, y) ({    \ 
typeof(x) _min1 = (x);   \ 
typeof(y) _min2 = (y);   \ 
(void) (&_min1 == &_min2);  \ 
_min1 < _min2 ? _min1 : _min2; }) 

Hãy xem bài viết này: GCC hacks in the Linux kernel

Khi tôi lần đầu tiên nhìn thấy này, tôi thực sự hỏi một câu hỏi ở đây trên SO về:

min macro in kernel.h

Tôi không hoàn toàn chắc chắn cách bạn sẽ sử dụng nó để giải quyết vấn đề của bạn, nhưng đó là một cái gì đó đáng xem t.

+0

đây không phải là loại kiểm tra thời gian chạy - vì C không được nhập động, gõ thông tin chỉ có sẵn tại thời điểm biên dịch – Christoph

1

Các loại biến thực sự được biết tại thời gian biên dịch, tuy nhiên việc mở rộng macro diễn ra trước khi biên dịch. Tôi đề nghị bạn thực hiện 2 chức năng quá tải thay vì một macro.

5

Bạn có thể kiểm tra các đặc điểm của các loại. Ví dụ: int có thể giữ giá trị âm, trong khi char* thì không thể. Vì vậy, nếu ((typeof(param))-1) < 0, param là unsigned:

if (((typeof(param))-1) < 0) { 
    do_something_with_int(); 
} else { 
    do_something_with_char_p(); 
} 

Trình biên dịch rõ ràng là tối ưu hóa này ra.

Hãy thử nó ở đây: http://ideone.com/et0v1

này sẽ dễ dàng hơn nếu các loại có kích cỡ khác nhau.Ví dụ, nếu bạn muốn viết một macro chung hơn có thể xử lý kích thước nhân vật khác nhau:

if (sizeof(param) == sizeof(char)) { 
    /* ... */ 
} else if (sizeof(param) == sizeof(char16_t)) { 
    /* ... */ 
} else if (sizeof(param) == sizeof(char32_t)) { 
    /* ... */ 
} else { 
    assert("incompatible type" && 0); 
} 

GCC có một chức năng được xây dựng trong __builtin_types_compatible_p() rằng có thể kiểm tra khả năng tương thích loại:

if (__builtin_types_compatible_p(typeof(param), int)) { 
    func_int(param); 
} else if (__builtin_types_compatible_p(typeof(param), char*)) { 
    func_string(param); 
} 

Thử tại đây: http://ideone.com/lEmYE

Bạn có thể đặt macro này vào macro để đạt được những gì bạn đang cố gắng làm:

#define FUNC(param) ({            \ 
    if (__builtin_types_compatible_p(typeof(param), int)) {   \ 
     func_int(param);            \ 
    } else if (__builtin_types_compatible_p(typeof(param), char*)) { \ 
     func_string(param);           \ 
    }                 \ 
}) 

(({...})GCC's statement expression, nó cho phép một nhóm báo cáo là giá trị.

Nội trang dựng sẵn __builtin_choose_expr() có thể chọn biểu thức để biên dịch. Với __builtin_types_compatible_p này cho phép để kích hoạt một lỗi tại thời gian biên dịch nếu loại param là không tương thích với cả intchar*: (bằng cách soạn somehting không hợp lệ trong trường hợp này)

#define FUNC(param)              \ 
    __builtin_choose_expr(__builtin_types_compatible_p(typeof(param), int) \ 
     , func_int(param)             \ 
     , __builtin_choose_expr(__builtin_types_compatible_p(typeof(param), char*) \ 
      , func_string(param)           \ 
      , /* The void expression results in a compile-time error  \ 
       when assigning the result to something. */    \ 
      ((void)0)              \ 
     )                 \ 
    ) 

Đây thực sự là một ví dụ thay đổi chút ít từ __builtin_choose_expr docs.

+0

'func_int (x);', 'func_string (x);' và đặt toàn bộ nội dung bên trong 'do {} trong khi (0)' –

+0

Tôi ban đầu không kèm theo mã trong 'do {} while()' vì đó không phải là macro ;-) – arnaud576875

+2

-1 'typeof' không phải là C mà còn là phần mở rộng gcc. Điều gì khiến bạn nghĩ rằng địa chỉ không thể có bộ bit 'đăng nhập'? –

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