Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add zero arguments function to _Generic macro

Tags:

c

gcc

macros

clang

c11

I am trying to generate overloaded functions using _Generic macro in C11, and I have stopped on zero arguments function support, e.g:

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

For now compiling and running:

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

goes without any problem, but:

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

throws error:

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

I am using:

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

GCC throws:

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

so I understand _Generic is not supported this version of gcc:

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

Is my problem even solvable or I just overestimate capabilities of _Generic, or I just need to upgrade my compilers to use this options properly ?

like image 777
mucka Avatar asked Apr 22 '15 14:04

mucka


2 Answers

C has variadic macros that may receive zero or more arguments

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

here the +0 in addition ensures that an array to pointer conversion is performed for your string argument, which you seem to assume.

The later is important since gcc and clang currently differ in their behavior if the selection expression is an array.

Edit: You probably also would want your macro to work if someone passes in a char const* so you should add that case, too.

like image 176
Jens Gustedt Avatar answered Sep 28 '22 06:09

Jens Gustedt


Your problem is not directly related to _Generics. You simply defined you macro #define msg(_1) with an argument, therefore you have to pass an argument.

If you don't rely on compiler extensions you cannot pass zero or more arguments to a _Generic macro. You will have to choose between zero or one arguments as shown here or, 1 or more.

This is my solution for any macro combination, but it involves a dummy argument. You can define you own type that will serve as an indicator of an emtpy macro

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)

And then call it with:

msg( msg_empty ) ;

Which will call the msg_none function.

like image 33
2501 Avatar answered Sep 28 '22 05:09

2501