2015-04-22 19 views
7

Tôi cố gắng để tạo ra các chức năng quá tải sử dụng vĩ mô _Generic tại C11, và tôi đã dừng lại trên không đối số hỗ trợ chức năng, ví dụ:Thêm zero đối số chức năng để _Generic vĩ mô

#define msg(_1) _Generic((_1), char*: msg_string, default: msg_none)(_1) 

char* msg_none(void){ 
    return moo_string("Have a nice day!"); 
} 

char* msg_string(char* message){ 
    int msglen = strlen(message); 
    char* result = malloc(msglen + 3); 
    sprintf(result, "<%s>\n", message); 
    return result; 
} 

Còn bây giờ biên dịch và chạy:

printf("%s",msg("hello!")); 

đi mà không có vấn đề gì, nhưng:

printf("%s",msg()); 

ném lỗi:

main.c:7:17: error: expected expression 
printf("%s",msg()); 

Tôi đang sử dụng:

clang --version 
clang version 3.5.0 (tags/RELEASE_350/final) 
Target: x86_64-pc-linux-gnu 
Thread model: posix 

GCC ném:

main.c:7:5: warning: implicit declaration of function ‘_Generic’ 

vì vậy tôi hiểu _Generic không được hỗ trợ phiên bản này của gcc:

gcc --version 
gcc (Gentoo 4.8.3 p1.1, pie-0.5.9) 4.8.3 

là vấn đề của tôi thậm chí có thể giải quyết được hoặc tôi chỉ đánh giá cao khả năng của _Generic, hoặc tôi chỉ cần nâng cấp trình biên dịch của tôi để sử dụng tùy chọn này đúng cách?

+0

1) '" hello! "' Có thể khớp 'char [7]' 2) 'msg_none (_1)' nhưng 'msg_none (void)' 3) 'char * result = malloc (msglen + 3) ; ':' + 3' phải là '+ 4' cho NUL. – BLUEPIXY

+1

'_Generic' GCC 4.9 [C11Status] (https://gcc.gnu.org/wiki/C11Status) – BLUEPIXY

+0

@BLUEPIXY, hôm nay họ đã chuyển gcc 5.1, trong đó có C11 (+ gnu extensions) làm mặc định. –

Trả lời

3

C có macro variadic có thể nhận được số không hay nhiều đối số

#define msg(...) _Generic((__VA_ARGS__+0), char*: msg_string, default: msg_none)(__VA_ARGS__) 

ở đây +0 ngoài đảm bảo rằng một mảng để chuyển đổi con trỏ được thực hiện cho đối số chuỗi của bạn, mà bạn có vẻ giả.

Điều sau là quan trọng vì gcc và tiếng kêu hiện tại khác nhau trong hành vi của chúng nếu biểu thức chọn là một mảng.

Chỉnh sửa: Bạn cũng có thể muốn macro của mình hoạt động nếu ai đó đi qua số char const* để bạn cũng nên thêm trường hợp đó.

+1

Huh, tôi không biết bạn có thể làm điều đó với _Generic. '(__VA_ARGS __ + 0)' điều này không thực sự làm việc với nhiều hơn một đối số mặc dù. – 2501

+0

Nhưng bạn đã trả lời câu hỏi như vậy ... + 1 – 2501

+0

Cảm ơn bạn rất nhiều! Đây là exacly những gì tôi đã được lookign cho, với '+ 0' các' printf ("% s", msg ((char *) "hello!")); 'Được giảm xuống' printf ("% s", msg ("hello!")); ', trường hợp đối số 0 hoạt động và thậm chí' #define msg (_1) _Generic ((_ 1 + 0), char *: msg_string, mặc định: msg_none) (_ 1) 'cú pháp cụ thể này hoạt động. – mucka

2

Sự cố của bạn không liên quan trực tiếp đến _Generics. Bạn chỉ cần định nghĩa macro của mình là #define msg(_1) với một đối số, do đó bạn phải vượt qua một đối số.

Nếu bạn không dựa vào các phần mở rộng trình biên dịch, bạn không thể chuyển số không hoặc nhiều đối số cho macro _Generic. Bạn sẽ phải chọn giữa 0 hoặc một đối số như được hiển thị here hoặc, 1 hoặc nhiều hơn.

Đây là giải pháp của tôi cho bất kỳ kết hợp macro nào, nhưng nó liên quan đến một đối số giả. Bạn có thể xác định bạn sở hữu kiểu đó sẽ đóng vai trò như một chỉ báo của một emtpy vĩ mô

typedef struct 
{ 
    int unused ; 
} emtpy ; 

const empty msg_empty = { 0 } ; 

char* msg_none(empty e) 
{ 
    (void)e ; 
    return moo_string("Have a nice day!"); 
} 

#define msg(_1) _Generic((_1), char*: msg_string, empty : msg_none)(_1) 

Và sau đó gọi nó với:

msg(msg_empty) ; 

Mà sẽ gọi hàm msg_none.

+1

"xác định loại của bạn" cho trống - giải pháp tốt đẹp! – chux

+0

@chux Cảm ơn bạn. Tôi muốn _Generics linh hoạt hơn. – 2501

+0

chắc chắn bạn có thể vượt qua số không hoặc nhiều đối số cho macro, xem câu trả lời của tôi –

0
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#define dummy void 
#define ARGS_AUX(_0, VAR, ...) VAR 
#define ARGS(...) ARGS_AUX(dummy, ##__VA_ARGS__, NULL) //gnu extensions 
#define MSG(var) (_Generic(var, char*: msg_string(var), default: msg_none())) 
#define msg(...) MSG(ARGS(__VA_ARGS__)) //MSG(NULL) when no argument 

char *moo_string(const char *s){ 
    return (char*)s; 
} 

char* msg_none(void){ 
    return moo_string("Have a nice day!"); 
} 

char* msg_string(char* message){ 
    int msglen = strlen(message); 
    char* result = malloc(msglen + 4); 
    sprintf(result, "<%s>\n", message); 
    return result; 
} 

int main(void){ 
    printf("%s\n", msg());//Have a nice day! 
    printf("%s\n", msg((char*)"hello!"));//<hello!>, type is char[7] when no cast 
    return 0; 
} 
Các vấn đề liên quan