2015-04-22 61 views
7

Próbuję wygenerować funkcje przeciążone użyciu _Generic makro w C11, i przestali na zerowe argumenty przemawiają funkcji, np:Dodaj zerowy argumenty funkcjonować do _Generic makro

#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; 
} 

Teraz kompilacja i uruchamianie:

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

idzie bez problemu, ale:

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

wyrzuca błąd:

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

Używam:

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

GCC rzuca:

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

więc rozumiem _Generic nie obsługuje tej wersji gcc:

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

jest mój problem nawet rozwiązywalne lub po prostu przeceniam możliwości _Generic, czy po prostu muszę uaktualnić moje kompilatory, aby poprawnie używać tych opcji?

+0

1) ' "Witam"' może dopasować char [7] '2)' msg_none (_1) 'ale' msg_none (void) '3) char * wynik = malloc (msglen + 3) ; ':' + 3' powinno być '+ 4' dla NUL. – BLUEPIXY

+1

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

+0

@BLUEPIXY, dzisiaj wysłano gcc 5.1, który ma C11 (+ rozszerzenia gnu) jako domyślny. –

Odpowiedz

3

C ma zmiennej liczbie argumentów makra, które mogą otrzymać zero lub więcej argumentów

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

tu +0 dodatkowo gwarantuje, że tablica wskaźnika konwersji odbywa się za argumencie, które zdają się zakładać.

Później jest ważna, ponieważ gcc szczęk obecnie różnią się w ich zachowaniu, gdy ekspresja wybór jest tablicą.

Edit: Prawdopodobnie również chciałby makra do pracy, jeśli ktoś przechodzi w char const* więc należy dodać, że przypadek, zbyt.

+1

Huh, nie wiedziałem, że możesz to zrobić z _Generic. '(__VA_ARGS __ + 0)' to jednak nie działa z więcej niż jednym argumentem. – 2501

+0

Ale odpowiedziałaś na pytanie, więc ... + 1 – 2501

+0

Dziękuję bardzo! To jest dokładnie to, czego szukałem, z '+ 0'' printf ("% s", msg ((char *) "cześć!")); 'Jest zredukowane do' printf ("% s", msg ("hello!")); ', Case z argumentem zerowym działa, a nawet' #define msg (_1) _Generic ((_ 1 + 0), char *: msg_string, default: msg_none) (_ 1) 'ta konkretna składnia działa. – mucka

2

Twój problem nie jest bezpośrednio związany z _Generics. Po prostu zdefiniowałeś makro #define msg(_1) z argumentem, dlatego musisz podać argument.

Jeśli nie polegasz na rozszerzeniach kompilatora, nie możesz przekazać zero lub więcej argumentów do makro _Generic. Będziesz musiał wybrać pomiędzy zero lub jeden argument, jak pokazano here lub 1 lub więcej.

To jest moje rozwiązanie dla każdej kombinacji makr, ale zawiera ona fałszywy argument. Można zdefiniować jesteś właścicielem typ, który będzie służyć jako wskaźnik w emtpy makro

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) 

a następnie wywołać go z:

msg(msg_empty) ; 

które będą wymagały funkcję msg_none.

+1

"Zdefiniuj własny typ" dla pustego - fajne rozwiązanie! – chux

+0

@chux Dziękuję. Chciałbym, żeby ludzie byli bardziej elastyczni. – 2501

+0

Oczywiście możesz przekazać zero lub więcej argumentów do makra, zobacz moją odpowiedź –

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; 
}