Arbitrary number of arguments of any type in C11 and higher using _Generic and variadic macros

C print function that accepts any number of arguments
C print function that accepts any number of arguments

About myself

I myself am a C ++ programmer, or rather, I am just a beginner, with no commercial experience. Initially, I got acquainted with the C language, and discovered C ++ as a powerful extension of the C language. In my opinion, it adds those necessary useful things that are not in C (function overloading, classes, namespaces, etc.), while these things perfectly expand the philosophy language





The idea

C 2011 "" . (Generic selection) , - ,





: () print



, . , , . C11









, . , :





  1. . . , , :









    1. ,





  2. " ",





  3. :









    1. __VA_ARGS__



      __VA_OPT__



      VA_ARGS



      VA_OPT.



      __LINE__ __FILE__







    2. : \



      , . 20 5 ,





    3. &



      &



      , <



      &lt;



      -





    4. -





  4. , ( 700) . . -





  5. , , . , . ! :) png









print(x)



int, float



char*



(cstring):





void print_int(int x) {printf("%d ", x); }

void print_float(float x) {printf("%.4f ", x); }
void print_string(char* x) {printf("%s ", x); }
      
      



print



:





#define print(x) _Generic((X),\
	int: print_int,\
  float: print_float,\
  char*: print_string)\
	(x)
  
      
      



, print("hi")



print_string("hi")



, print(5.5)



print_float(5.5)







print("hi")



_Generic(("hi"), int: print_int, float: print_float, char*: print_string)("hi"),



, _Generic(...)







. print_int







void print_int(int n, ...)
{
  va_list argptr;
  va_start(argptr, n);
  int x;
  for (int i = 0; i < n; i++)
  {
    x = va_arg(argptr, int);
    printf("%d ", x);
  }
  va_end(argptr);
}
      
      



, :) n



,





PP_NARG(...),
#ifndef PP_NARG

/* 
* 
*	The PP_NARG macro returns the number of arguments that have been
*	passed to it.
* 
*	https://groups.google.com/g/comp.std.c/c/d-6Mj5Lko_s
* 
*/

#define PP_NARG(...) \
	PP_NARG_(__VA_ARGS__,PP_RSEQ_N())

#define PP_NARG_(...) \
	PP_ARG_N(__VA_ARGS__)

#define PP_ARG_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63, N, ...) N

#define PP_RSEQ_N() \
63,62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
39,38,37,36,35,34,33,32,31,30, \
29,28,27,26,25,24,23,22,21,20, \
19,18,17,16,15,14,13,12,11,10, \
9,8,7,6,5,4,3,2,1,0

#endif

      
      



#define print(...)    print_int(PP_NARG(__VA_ARGS__), __VA_ARGS__)
      
      



: __VA_ARGS__



, ...







, ,





#define function(x, ...) Generic((x),\
	int: function_int,\
  float: function_float,\
  char*: function_string)\
(PP_NARG(__VA_ARGS__) + 1, x, __VA_ARGS__)
      
      



function



, . function



, print



, . , , ,





I.

( ) hidden_print(sep, n, x1, x2, x3, ...),



xi



printf.





12. print



' .





cool



. - , , , , . c++ cool



, , . #define print cool_print



, #undef print







cool_hidden_types[12]



, cool_hidden_last



, cool_hidden_add_int



, cool_hidden_add_float



.. , . 7 : int, char*, float, double, char (?), uint, long







char (?)

- _Generic(('a'), char: fun_char)()



- " int



", int







#define



, enum



. , !





#define COOL_HIDDEN_INT 0
#define COOL_HIDDEN_STRING 1
#define COOL_HIDDEN_FLOAT 2
#define COOL_HIDDEN_DOUBLE 3
#define COOL_HIDDEN_CHAR 4
#define COOL_HIDDEN_UINT 5
#define COOL_HIDDEN_LONG 6
#define COOL_HIDDEN_VOID 7

int cool_hidden_types[12];
int cool_hidden_last = 0;

void cool_hidden_add_int()
{
    cool_hidden_types[cool_hidden_last] = COOL_HIDDEN_INT;
    cool_hidden_last += 1;
}
void cool_hidden_add_string()
{
    cool_hidden_types[cool_hidden_last] = COOL_HIDDEN_STRING;
    cool_hidden_last += 1;
}
/*    */
void cool_hidden_add_void()
{
    cool_hidden_types[cool_hidden_last] = COOL_HIDDEN_VOID;
    cool_hidden_last += 1;
}
      
      



COOL_HIDDEN_VOID



, . 16- ,





generic cool_hidden_add(x)



, x







#define cool_hidden_add(x)          \
    _Generic((x),       \
    int: cool_hidden_add_int,       \
    char*: cool_hidden_add_string, \
    float: cool_hidden_add_float, \
    double: cool_hidden_add_double, \
    char: cool_hidden_add_char, \
    unsigned int: cool_hidden_add_uint, \
    long: cool_hidden_add_long, \
    default: cool_hidden_add_void \
)()
      
      



...





II.

, cool_print##n(x1, x2, ..., xn)



("##" n



), xi



, cool_hidden_print(sep, n, x1, x2, ...)



, n



, xi



. ( ) cool_print_sep = " "



,





. , . ( visual studio , , )





     :
#define cool_print_n(x1, x2, x3, x4, ..., xn, ...)\
  cool_hidden_add(x1);\
  cool_hidden_add(x2);\
  cool_hidden_add(x3);\
  cool_hidden_add(x4);\
  ................... \
  cool_hidden_add(xn);\
cool_hidden_print(cool_print_sep, n, x1, x2, x3, x4, ..., xn)

      
      



//hide this a big part of code
#if 1 

#define cool_print_12(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, ...)   \
    cool_hidden_add(x1); \
    cool_hidden_add(x2); \
    cool_hidden_add(x3); \
    cool_hidden_add(x4); \
    cool_hidden_add(x5); \
    cool_hidden_add(x6); \
    cool_hidden_add(x7); \
    cool_hidden_add(x8); \
    cool_hidden_add(x9); \
    cool_hidden_add(x10); \
    cool_hidden_add(x11); \
    cool_hidden_add(x12); \
    cool_hidden_print(cool_print_sep, 12, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12)

#define cool_print_11(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, ...)   \
    cool_hidden_add(x1); \
    cool_hidden_add(x2); \
    cool_hidden_add(x3); \
    cool_hidden_add(x4); \
    cool_hidden_add(x5); \
    cool_hidden_add(x6); \
    cool_hidden_add(x7); \
    cool_hidden_add(x8); \
    cool_hidden_add(x9); \
    cool_hidden_add(x10); \
    cool_hidden_add(x11); \
    cool_hidden_print(cool_print_sep, 11, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11)

#define cool_print_10(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, ...)   \
    cool_hidden_add(x1); \
    cool_hidden_add(x2); \
    cool_hidden_add(x3); \
    cool_hidden_add(x4); \
    cool_hidden_add(x5); \
    cool_hidden_add(x6); \
    cool_hidden_add(x7); \
    cool_hidden_add(x8); \
    cool_hidden_add(x9); \
    cool_hidden_add(x10); \
    cool_hidden_print(cool_print_sep, 10, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10)

#define cool_print_9(x1, x2, x3, x4, x5, x6, x7, x8, x9, ...)   \
    cool_hidden_add(x1); \
    cool_hidden_add(x2); \
    cool_hidden_add(x3); \
    cool_hidden_add(x4); \
    cool_hidden_add(x5); \
    cool_hidden_add(x6); \
    cool_hidden_add(x7); \
    cool_hidden_add(x8); \
    cool_hidden_add(x9); \
    cool_hidden_print(cool_print_sep, 9, x1, x2, x3, x4, x5, x6, x7, x8, x9)

#define cool_print_8(x1, x2, x3, x4, x5, x6, x7, x8, ...)   \
    cool_hidden_add(x1); \
    cool_hidden_add(x2); \
    cool_hidden_add(x3); \
    cool_hidden_add(x4); \
    cool_hidden_add(x5); \
    cool_hidden_add(x6); \
    cool_hidden_add(x7); \
    cool_hidden_add(x8); \
    cool_hidden_print(cool_print_sep, 8, x1, x2, x3, x4, x5, x6, x7, x8)

#define cool_print_7(x1, x2, x3, x4, x5, x6, x7, ...)   \
    cool_hidden_add(x1); \
    cool_hidden_add(x2); \
    cool_hidden_add(x3); \
    cool_hidden_add(x4); \
    cool_hidden_add(x5); \
    cool_hidden_add(x6); \
    cool_hidden_add(x7); \
    cool_hidden_print(cool_print_sep, 7, x1, x2, x3, x4, x5, x6, x7)

#define cool_print_6(x1, x2, x3, x4, x5, x6, ...)   \
    cool_hidden_add(x1); \
    cool_hidden_add(x2); \
    cool_hidden_add(x3); \
    cool_hidden_add(x4); \
    cool_hidden_add(x5); \
    cool_hidden_add(x6); \
    cool_hidden_print(cool_print_sep, 6, x1, x2, x3, x4, x5, x6)


#define cool_print_5(x1, x2, x3, x4, x5, ...)   \
    cool_hidden_add(x1); \
    cool_hidden_add(x2); \
    cool_hidden_add(x3); \
    cool_hidden_add(x4); \
    cool_hidden_add(x5); \
    cool_hidden_print(cool_print_sep, 5, x1, x2, x3, x4, x5)

#define cool_print_4(x1, x2, x3, x4, ...)   \
    cool_hidden_add(x1); \
    cool_hidden_add(x2); \
    cool_hidden_add(x3); \
    cool_hidden_add(x4); \
    cool_hidden_print(cool_print_sep, 4, x1, x2, x3, x4)

#define cool_print_3(x1, x2, x3, ...)   \
    cool_hidden_add(x1); \
    cool_hidden_add(x2); \
    cool_hidden_add(x3); \
    cool_hidden_print(cool_print_sep, 3, x1, x2, x3)

#define cool_print_2(x1, x2, ...)   \
    cool_hidden_add(x1); \
    cool_hidden_add(x2); \
    cool_hidden_print(cool_print_sep, 2, x1, x2)

#define cool_print_1(x, ...)   \
    cool_hidden_add(x); \
    cool_hidden_print(cool_print_sep, 1, x)


#endif //hide this a big part of code

      
      



, cool_print_n



12, ...



,





PP_NARG(__VA_ARGS__



) cool_print_##PP_NARG(__VA_ARGS__)



, - cool_print_PP_NARG("x", 5, "i", 8,),



. , ,





PP_NARG(__VA_ARGS__)
#ifndef PP_NARG

/* 
* 
*	The PP_NARG macro returns the number of arguments that have been
*	passed to it.
* 
*	https://groups.google.com/g/comp.std.c/c/d-6Mj5Lko_s
* 
*/

#define PP_NARG(...) \
	PP_NARG_(__VA_ARGS__,PP_RSEQ_N())

#define PP_NARG_(...) \
	PP_ARG_N(__VA_ARGS__)

#define PP_ARG_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63, N, ...) N

#define PP_RSEQ_N() \
63,62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
39,38,37,36,35,34,33,32,31,30, \
29,28,27,26,25,24,23,22,21,20, \
19,18,17,16,15,14,13,12,11,10, \
9,8,7,6,5,4,3,2,1,0

#endif


      
      



cool_print(...) - PP_NARG,

#define cool_print(...) \
	cool_print_(__VA_ARGS__ , COOL_RSEQ_N())


#define cool_print_(...) \
	COOL_ARG_N(__VA_ARGS__)

#define COOL_ARG_N( \
    _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
    _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
    _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
    _61,_62,_63, n, ...) \
                        \
    cool_print_##n(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11,_12)

#define COOL_RSEQ_N() \
    63,62,61,60,59,58,57,56,55,54,53,52,51,50, \
    49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30, \
    29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10, \
    9,8,7,6,5,4,3,2,1,0


      
      



:





1. 	   cool_print("a", 4, "b")

2. 	   cool_print_("a", 4, "b", 
		63,62,61,60,59,58,57,56,55,54,
		53,52,51,50,49,48,47,46,45,44,43,
		42,41,40,39,38,37,36,35,34,33,32,
		31,30,29,28,27,26,25,24,23,22,21,
		20,19,18,17,16,15,14,13,12,11,10,
		9,8,7,6,5,4,3,2,1,0

3. 	  cool_print_      COOL_ARG_N,
       64 .  64- ,  n
          - ,  
      VA_ARGS   COOL_RSEQ_N 
    (63..0)      

4.	     COOL_ARG_N  
		cool_print_##n    . 
		    cool_print_3

	cool_print_3("a", 4, "b", 
	63,62,61,60,59,58,57,56,55,54,53,52,51,50,
	49,48,47,46,45,44,43,42,41,40,39,38,37,36,
	35,34,33,32,31,30,29,28,27,26,25,24,23,22,
	21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3)

  12 ,     . 
    ,    "..."    
 cool_print_##n     

         64  12, 
      

      
      



III.

, cool_print("", "", 10)



cool_hidden_types



, cool_hidden_print(int sep, int n, ...)



!





C

<stdarg.h>



, . :





  1. ...







  2. va_list argptr



    - argptr



    ,





  3. va_start(argptr, n)



    -





  4. va_arg(argptr, float)



    -





  5. va_end(argptr)



    -





- ,





: . swich'e void' x, printf("...%s", *((type) x), sep)



, type



- , "..." - . int



printf("%d%s", *((type) x), sep)



. #define COOL_CAST(T, x) ((T) (x))







cool_hidden_print(sep, n, ...)
#define COOL_CAST(T, x) ((T) (x))


void cool_hidden_print(char* sep, int n, ...)
{
    va_list argptr;
    va_start(argptr, n);
void* x;

for (int i = 0; i &lt; n; i++)
{
    switch (cool_hidden_types[i])
    {
    case COOL_HIDDEN_INT:
        x = &va_arg(argptr, int);
        printf("%d%s", COOL_CAST(int, x), sep);
        break;

    case COOL_HIDDEN_STRING:
        x = &va_arg(argptr, char*);
        printf("%s%s", COOL_CAST(char*, x) , sep);
        break;

    case COOL_HIDDEN_FLOAT:
        x = &va_arg(argptr, float);
        printf("%.4f%s", COOL_CAST(float, x), sep);
        break;

    case COOL_HIDDEN_DOUBLE:
        x = &va_arg(argptr, double);
        printf("%.4f%s", COOL_CAST(double, x), sep);
        break;

    case COOL_HIDDEN_CHAR:
        x = &va_arg(argptr, char);
        printf("%c%s", COOL_CAST(char, x), sep);
        break;

    case COOL_HIDDEN_UINT:
        x = &va_arg(argptr, unsigned int);
        printf("%.4u%s", COOL_CAST(unsigned int, x), sep);
        break;

    case COOL_HIDDEN_VOID:
        printf("unsupported type%s", sep);
        break;

    default:
        printf("Internal COOL/C/PRINT error line: %d in %s", __LINE__, __FILE__);
        break;
    } 
}

va_end(argptr);
cool_hidden_last = 0;

}
      
      



, , . va_arg



printf







cool_







#define print cool_print







, print



! println



,





#define cool_println(...) \
		cool_print(__VA_ARGS__);    printf("\n")

#define cool_printlnn() printf("\n")
      
      



, - , printlnn()



... , cool_print







 
#define cool_print(...) cool_print_(__VA_ARGS__ , ## COOL_RSEQ_N()
 
#define cool_print(...) cool_print_(__VA_ARGS__ ## , COOL_RSEQ_N()
   
      
      



. ,## __VA_ARGS__



, __VA_ARGS__



,





- , __VA_ARGS__



. 2





__VAR_OPT__



, , , , ,





- (,)



, visual stidio __VAR_OPT__



. __VAR_OPT__



, 63 64 ( cool_print##n



( ). -





#define cool_print(...)\
	__VAR_OPT__(  cool_print_(__VA_ARGS__ , COOL_RSEQ_N())  )
 
#define cool_print(...) \
	cool_print_(__VA_ARGS__ , COOL_RSEQ_N())
      
      



- ,





#define cool_print(...)\
    cool_print_("", __VA_ARGS__)

#define cool_print_(...) \
	cool_print__(__VA_ARGS__ , COOL_RSEQ_N())


#define cool_print__(...) \
	COOL_ARG_N(__VA_ARGS__)
      
      



,






  • - . , ,





  • - . C++ . , print







  • - . visual studio print



    println



    " ", ( ) . . , variadic templates c++, ( - )





    . ,





At the same time it compiles perfectly






: print.h





c_example.c





. . , - . C++, , id ; , ( pow, powi, powf



); , , , , . -





print



C++:





print C++
#ifndef COOL_PRINT_HPP
#define COOL_PRINT_HPP

#include <string>
#include <iostream>
#include <iomanip>

namespace
{
	std::ostream* out = &std::cout;
}

namespace cool
{
	inline void setCyrillic()
	{
		setlocale(LC_ALL, "Russian");
	}

	void setPrintOut(std::ostream& os)
	{
		::out = &os;
	}

	std::ostream* getPrintOutPtr()
	{
		return ::out;
	}
	
	inline void printFlush()
	{
		*::out << std::flush;
	}

	inline void print() 
	{ 
		*::out << ' ';
	}

	template <typename Arg>
	inline void print(const Arg& arg)
	{
		*::out <<  std::fixed << std::setprecision(4) << arg << ' ';
	}

	template <typename Arg, typename... Args>
	void print(const Arg& arg, const Args&... args)
	{
		print(arg);
		print(args...);
	}
	////

	inline void println()
	{
		*::out << '\n';
	}
	template <typename Arg>
	inline void println(const Arg& arg)
	{
		*::out << std::fixed << std::setprecision(4) << arg << '\n';
	}

	template <typename... Args>
	void println(const Args&... args)
	{
		print(args...);
		println();
	}
	///
	void print0() { }

	template <typename Arg>
	inline void print0(const Arg& arg)
	{
		*::out << std::fixed << std::setprecision(4) << arg;
	}

	template <typename Arg, typename... Args>
	void print0(const Arg& arg, const Args&... args)
	{
		print0(arg);
		print0(args...);
	}

#define COOL_INFO(x) (std::string(#x) + " = " + std::to_string(x))
}


#endif

      
      



More understandable, about 3 times less code, and the implementation is more complete. But at the same time, the standard one, printf



although it does not look so elegant, is fast and practical. Each language has its place








All Articles