2

I have read _Generic combined with variadic function?

http://www.robertgamble.net/2012/01/c11-generic-selections.html

but I want to make print just like python receive multi and unknown type parameters

print("a", 1) //printf("%s %d", "a", 1)

here's my code

//compiler gcc
#define COUNT(...) ({register int i;int c=1;for(i=0;i<=(strlen(#__VA_ARGS__));i++){if (#__VA_ARGS__[i]==','){c++;}};c;})


#define _print(object) printf( _Generic((object),  \
        _Bool: "bool%d",                  unsigned char: "%hhu",          \
         char: "%c",                     signed char: "%hhd",            \
    short int: "%d",         unsigned short int:"%d",     \
          int: "%d",                     unsigned int: "%u",           \
     long int: "%lu",           unsigned long int: "%lu",      \
long long int: "%llu", unsigned long long int: "%llu", \
        float: "%f",                         double: "%f",                 \
  long double: "%Lf",                   char *: "%s",        \
       void *: "%p",                int *: "%p",         \
      default: "<unknow object at %p>") , object)
void pyprint(int LEN, ...){
    va_list ap;
    va_start(ap, LEN);int i;
    for (int i = 0; i < LEN; i++)
    {
        _print(va_arg(ap, int));
    } }
#define print(...) pyprint(COUNT(__VA_ARGS__), __VA_ARGS__)
//print('A', 10, -10);  ->6510-10
//but print only receive int object because va_arg(ap, int)
ianfun
  • 411
  • 5
  • 10
  • ianfun, [Formatted print without the need to specify type matching specifiers using _Generic](https://codereview.stackexchange.com/q/115143/29485) may interest you. – chux - Reinstate Monica May 21 '21 at 02:06
  • [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) would help to reproduce – thirdeye May 21 '21 at 02:18
  • 1
    Don't forget that in C, `'A'` is an [integer character constant](http://port70.net/~nsz/c/c11/n1570.html#6.4.4.4) (see especially [¶10](http://port70.net/~nsz/c/c11/n1570.html#6.4.4.4p10)) — of type `int` and not type `char`. C++ is different. – Jonathan Leffler May 21 '21 at 02:45
  • I believe your COUNT macro will be confused if any of the strings you pass to the `print` macro themselves contain commas. You have an unused variable `int i;` in the `pyprint()` function — it's hidden by the `i` in `for (int i = 0; …)`. – Jonathan Leffler May 21 '21 at 03:07
  • I forgot to write `va_end(ap);` in pyprint – ianfun May 21 '21 at 05:03
  • @Jonathan Leffler gcc say `i` in `pyprint` is undeclared until `int i;` – ianfun May 21 '21 at 05:12
  • You appear to have `int i;` followed immediately by `for (int i = 0; i < LEN; i++)`. The first `int i;` is unused because there is a second `int i` in the nested scope of the controls of the `for` loop. You don't, therefore, need the first `int i;`. – Jonathan Leffler May 21 '21 at 05:15

1 Answers1

1

The bad news is that COUNT macro will not work if one of arguments has a comma in it. Typical examples would be fun(1,2) or "Hello, Bob!".

I suggest using a macro to count arguments however it limits maximal number of arguments that are supported.

The macro works by adding a list of consecutive integers after expanded VA_ARGS list. As result the argument on a specific position will contain a number of arguments passed to the macro.

#define print(...) print_(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0);
#define print_(a0, a1, a2, a3, a4, a5, a6, a7, CNT, ...) \
do {                              \
    if (CNT > 0) _print(a0); \
    if (CNT > 1) _print(a1); \
    if (CNT > 2) _print(a2); \
    if (CNT > 3) _print(a3); \
    if (CNT > 4) _print(a4); \
    if (CNT > 5) _print(a5); \
    if (CNT > 6) _print(a6); \
    if (CNT > 7) _print(a7); \
    puts("");                \
} while (0)

The solution can handle up to 8 arguments but this limitation can be easily lifted. Usage:

int main() {
    print("a");
    print(3, " / ", 2, " = ", 1.5);
    print('A', 10, -10);
    char a = 'A';
    print(a, 10, -10);
}

prints

a
3 / 2 = 1.500000
6510-10
A10-10

The problem of printing 'A' as an integer cannot be easily solved because C standard requires character literals to be of type int. See `character constant

tstanisl
  • 13,520
  • 2
  • 25
  • 40
  • how about this `#define COUNT(...) ({int bool=0;int c=1;for(int i=0;i<=(strlen(#__VA_ARGS__));i++){if (#__VA_ARGS__[i]==','){if (!bool) c++;}else{if (#__VA_ARGS__[i]=='\'' || #__VA_ARGS__[i]=='\"'){if(bool)bool=0;else{bool=1;}}};}c;})`see also[link](https://stackoverflow.com/questions/2124339/c-preprocessor-va-args-number-of-arguments) – ianfun May 21 '21 at 09:03
  • @ianfun it would still fail for function calls like `print(foo(1,2))`. It is required to parse arbitrary C expression to make this thing work. – tstanisl May 21 '21 at 09:06