7

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 ?

4
  • 1) "hello!" might match char[7] 2) msg_none(_1) but msg_none(void) 3) char* result = malloc(msglen + 3); : +3 should be +4 for NUL. Commented Apr 22, 2015 at 15:12
  • 1
    _Generic GCC 4.9 C11Status Commented Apr 22, 2015 at 15:21
  • @BLUEPIXY, today they shipped gcc 5.1, which has C11 (+gnu extensions) as a default. Commented Apr 22, 2015 at 22:12
  • Sory, I actually used printf("%s",msg((char*)"hello!")); so it worked anyway, but +0 solution from below solves even this problem. Commented Apr 23, 2015 at 6:56

3 Answers 3

3

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Huh, I didn't know you could do that with _Generic. (__VA_ARGS__+0) this doesn't really work with more than one argument though.
But you did answer the question so...+1
Thank you very much ! This is exacly what I was lookign for, with +0 the printf("%s",msg((char*)"hello!")); is reduced to printf("%s",msg("hello!"));, zero argument case works and even #define msg(_1) _Generic((_1+0), char*: msg_string, default: msg_none)(_1) this particular syntax works.
2

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.

3 Comments

"define you own type" for empty - nice solution!
@chux Thank you. I wish _Generics were more flexible.
sure you can pass zero or more arguments to a macro, see my answer
1
#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;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.