una sumar suma seleccionadas repetidos rangos rango que para macro funcion filas datos cumplan contar condición columna celdas alguna c macros arguments variadic

seleccionadas - macro para sumar rangos variables



Macro para contar el número de argumentos (4)

El ejemplo completo en la respuesta de Mehrwolf desafortunadamente no se compila en VS2010 ni en VS2015 (lo probé también en este compilador VS en línea). Un enfoque diferente sobre este problema que permite producir código multiplataforma que compila en una amplia gama de compiladores utiliza extensiones no estándar que también están disponibles en compiladores de MS como en mi respuesta a una pregunta similar. Además, de forma diferente a la respuesta citada, el resultado de PP_NARG((a, b, c)) usar las extensiones (en los compiladores MS y gcc / clang) es 1 y no 0.

Tengo una función variadic de una biblioteca de C de terceros:

int func(int argc, ...);

argc indica el número de argumentos opcionales pasados. Lo estoy envolviendo con una macro que cuenta el número de argumentos, como se sugiere aquí . Para mayor comodidad de lectura, esta es la macro:

#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 #define PP_NARG_(...) PP_ARG_N(__VA_ARGS__) #define PP_NARG(...) PP_NARG_(__VA_ARGS__, PP_RSEQ_N())

y lo estoy envolviendo así:

#define my_func(...) func(PP_NARG(__VA_ARGS__), __VA_ARGS__)

La macro PP_NARG funciona muy bien para las funciones que aceptan uno o más argumentos. Por ejemplo, PP_NARG("Hello", "World") evalúa a 2 .

El problema es que cuando no se pasan argumentos, PP_NARG() evalúa a 1 lugar de 0 .
Entiendo cómo funciona esta macro , pero no se me ocurre una idea para modificarla para que también se comporte correctamente en este caso.

¿Algunas ideas?

EDITAR :
Encontré una solución para PP_NARG y la PP_NARG como respuesta.
Todavía tengo problemas con envolver la función variadic sin embargo. Cuando __VA_ARGS__ está vacío, my_func expande a func(0, ) que desencadena un error de compilación.


Es posible hacerlo en GCC usando la extensió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 /* Note 63 is removed */ #define PP_RSEQ_N() / 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 #define PP_NARG_(...) PP_ARG_N(__VA_ARGS__) /* Note dummy first argument _ and ##__VA_ARGS__ instead of __VA_ARGS__ */ #define PP_NARG(...) PP_NARG_(_, ##__VA_ARGS__, PP_RSEQ_N()) #define my_func(...) func(PP_NARG(__VA_ARGS__), __VA_ARGS__)

Ahora PP_NARG(a, b, c) da 3 y PP_NARG() da 0.

Lamentablemente, no veo una manera de que funcione en general.


Otra posibilidad, que no usa sizeof ni una extensión GCC es agregar lo siguiente a tu código

#define PP_COMMASEQ_N() / 1, 1, 1, 1, / 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, / 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, / 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, / 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, / 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, / 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 #define PP_COMMA(...) , #define PP_HASCOMMA(...) / PP_NARG_(__VA_ARGS__, PP_COMMASEQ_N()) #define PP_NARG(...) / PP_NARG_HELPER1( / PP_HASCOMMA(__VA_ARGS__), / PP_HASCOMMA(PP_COMMA __VA_ARGS__ ()), / PP_NARG_(__VA_ARGS__, PP_RSEQ_N())) #define PP_NARG_HELPER1(a, b, N) PP_NARG_HELPER2(a, b, N) #define PP_NARG_HELPER2(a, b, N) PP_NARG_HELPER3_ ## a ## b(N) #define PP_NARG_HELPER3_01(N) 0 #define PP_NARG_HELPER3_00(N) 1 #define PP_NARG_HELPER3_11(N) N

El resultado es

PP_NARG() // expands to 0 PP_NARG(x) // expands to 1 PP_NARG(x, 2) // expands to 2

Explicación:

El truco en estas macros es que PP_HASCOMMA(...) expande a 0 cuando se llama con cero o un argumento y a 1 cuando se llama con al menos dos argumentos. Para distinguir entre estos dos casos, utilicé PP_COMMA __VA_ARGS__ () , que devuelve una coma cuando __VA_ARGS__ está vacía y no devuelve nada cuando __VA_ARGS__ no está vacío.

Ahora hay tres posibles casos:

  1. __VA_ARGS__ está vacío: PP_HASCOMMA(__VA_ARGS__) devuelve 0 y PP_HASCOMMA(PP_COMMA __VA_ARGS__ ()) devuelve 1.

  2. __VA_ARGS__ contiene un argumento: PP_HASCOMMA(__VA_ARGS__) devuelve 0 y PP_HASCOMMA(PP_COMMA __VA_ARGS__ ()) devuelve 0.

  3. __VA_ARGS__ contiene dos o más argumentos: PP_HASCOMMA(__VA_ARGS__) devuelve 1 y PP_HASCOMMA(PP_COMMA __VA_ARGS__ ()) devuelve 1.

Las macros PP_NARG_HELPERx solo son necesarias para resolver estos casos.

Editar:

Para solucionar el problema de func(0, ) , debemos probar si hemos proporcionado cero o más argumentos. La macro PP_ISZERO entra en juego aquí.

#define PP_ISZERO(x) PP_HASCOMMA(PP_ISZERO_HELPER_ ## x) #define PP_ISZERO_HELPER_0 ,

Ahora definamos otra macro que precede la cantidad de argumentos a una lista de argumentos:

#define PP_PREPEND_NARG(...) / PP_PREPEND_NARG_HELPER1(PP_NARG(__VA_ARGS__), __VA_ARGS__) #define PP_PREPEND_NARG_HELPER1(N, ...) / PP_PREPEND_NARG_HELPER2(PP_ISZERO(N), N, __VA_ARGS__) #define PP_PREPEND_NARG_HELPER2(z, N, ...) / PP_PREPEND_NARG_HELPER3(z, N, __VA_ARGS__) #define PP_PREPEND_NARG_HELPER3(z, N, ...) / PP_PREPEND_NARG_HELPER4_ ## z (N, __VA_ARGS__) #define PP_PREPEND_NARG_HELPER4_1(N, ...) 0 #define PP_PREPEND_NARG_HELPER4_0(N, ...) N, __VA_ARGS__

Los muchos auxiliares se necesitan nuevamente para expandir las macros a valores numéricos. Finalmente probarlo:

#define my_func(...) func(PP_PREPEND_NARG(__VA_ARGS__)) my_func() // expands to func(0) my_func(x) // expands to func(1, x) my_func(x, y) // expands to func(2, x, y) my_func(x, y, z) // expands to func(3, x, y, z)

Ejemplo en línea:

http://coliru.stacked-crooked.com/a/73b4b6d75d45a1c8

Ver también:

Por favor, eche un vistazo al proyecto P99 , que tiene soluciones de preprocesador mucho más avanzadas, como estas .


Se me ocurrió la siguiente solución para PP_NARG :

#define PP_NARG(...)     (sizeof(#__VA_ARGS__) - 1 ? / PP_NARG_(__VA_ARGS__, PP_RSEQ_N()) : 0)

Cadena __VA_ARGS__ , por lo que si está vacía, su longitud es igual a 1 (porque #__VA_ARGS__ == ''/0'' ).
Funciona con -std=c99 -pedantic .

Todavía tengo problemas con envolver la función variadic sin embargo. Cuando __VA_ARGS__ está vacío, my_func expande a func(0, ) que desencadena un error de compilación.