mucka
mucka

Reputation: 1335

Add zero arguments function to _Generic macro

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 ?

Upvotes: 7

Views: 848

Answers (3)

BLUEPIXY
BLUEPIXY

Reputation: 40145

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

Upvotes: 1

2501
2501

Reputation: 25753

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.

Upvotes: 2

Jens Gustedt
Jens Gustedt

Reputation: 78923

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.

Upvotes: 3

Related Questions