Número arbitrario de argumentos de cualquier tipo en C11 y superior utilizando macros _Generic y variadic

Función de impresión C que acepta cualquier número de argumentos
Función de impresión C que acepta cualquier número de argumentos

Sobre mí

Yo mismo soy programador en C ++, o mejor dicho, soy un principiante, sin experiencia comercial. Inicialmente, me familiaricé con el lenguaje C y descubrí C ++ como una poderosa extensión del lenguaje C. En mi opinión, agrega aquellas cosas útiles necesarias que no están en C (sobrecarga de funciones, clases, espacios de nombres, etc.) , mientras que estas cosas expanden perfectamente el lenguaje filosófico





La 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++, ( - )





    . ,





Al mismo tiempo, se compila perfectamente






: 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

      
      



Más comprensible, aproximadamente 3 veces menos código y la implementación es más completa. Pero al mismo tiempo, el estándar, printf



aunque no parece tan elegante, es rápido y práctico. Cada idioma tiene su lugar








All Articles