validar usar sirve que posicional por parametros para linea explicacion como comandos argumentos argumento c variadic-functions

usar - ¿Cómo contar el número de argumentos pasados a una función que acepta un número variable de argumentos?



parametros por linea de comandos c (11)

Cómo contar el número de argumentos pasados ​​a la función en el siguiente programa:

#include<stdio.h> #include<stdarg.h> void varfun(int i, ...); int main(){ varfun(1, 2, 3, 4, 5, 6); return 0; } void varfun(int n_args, ...){ va_list ap; int i, t; va_start(ap, n_args); for(i=0;t = va_arg(ap, int);i++){ printf("%d", t); } va_end(ap); }

La salida de este programa sobre mi compilador gcc bajo ubuntu 10.04:

234561345138032514932134513792

Entonces, ¿cómo encontrar cuántos no. De los argumentos realmente pasados ​​a la función?


Anexar o NULL al final me permite tener cualquier cantidad de argumentos y no preocuparme de que se salga de la pila

#include <cstdarg> template<typename _Ty> inline void variadic_fun1(_Ty param1,...) { va_list arg1; //TO_DO va_end(arg1); } template<typename _Ty> void variadic_fun2(_Ty param1,...) { va_list arg1; va_start(arg1, param1); variadic_fun1(param1, arg1, 0); va_end(arg1); }


En este código es posible cuando solo se pasa puntero.

# include <unistd.h> # include <stdarg.h> # include <string.h> # include <errno.h> size_t __print__(char * str1, ...); # define print(...) __print__(NULL, __VA_ARGS__, NULL) # define ENDL "/n" int main() { print("1", ENDL, "2", ENDL, "3", ENDL); return 0; } size_t __print__(char * str1, ...) { va_list args; va_start(args, str1); size_t out_char = 0; char * tmp_str; while((tmp_str = va_arg(args, char *)) != NULL) out_char = out_char + write(1, tmp_str,strlen(tmp_str)); va_end(args); return out_char; }


Es posible y es simple, solo agregue otra variable k en el bucle y asigne inicialmente 1, pruebe este código

#include <stdio.h> #include <stdarg.h> void varfun(int i, ...); int main(){ varfun(1,2); return 0; } void varfun(int n_args, ...) { va_list ap; int i, t, k; k = 1; va_start(ap, n_args); for(i=0;i <= va_arg(ap, int);i++){ k+=1; } printf("%d",k); va_end(ap); }


La forma más segura es como se describe anteriormente. Pero si REALMENTE necesita saber la cantidad de argumentos sin agregar el argumento adicional mencionado, entonces puede hacerlo de esta manera (pero tenga en cuenta que es muy dependiente de la máquina, depende del sistema operativo e incluso, en raras ocasiones, depende del compilador). Ejecuté este código usando Visual Studio 2013 en un DELL E6440 de 64 bits.

Otro punto, en el punto en el que dividí por tamaño de (int), fue porque todos mis argumentos eran int. Si tiene argumentos de diferente tamaño, hay que ajustarme allí.

Esto se basa en el programa de llamada para utilizar la convención de llamada estándar de C. (varfun () obtiene el número de argumentos de "add esp, xxx" y hay dos formas de agregar, (1) forma corta y (2) forma larga. En la segunda prueba pasé una estructura porque quería simular muchos argumentos para forzar la forma larga).

Las respuestas impresas serán 6 y 501.

varfun(1, 2, 3, 4, 5, 6); 00A03CC8 6A 06 push 6 00A03CCA 6A 05 push 5 00A03CCC 6A 04 push 4 00A03CCE 6A 03 push 3 00A03CD0 6A 02 push 2 00A03CD2 6A 01 push 1 00A03CD4 E8 E5 D3 FF FF call _varfun (0A010BEh) 00A03CD9 83 C4 18 add esp,18h varfun(1, x); 00A03CDC 81 EC D0 07 00 00 sub esp,7D0h 00A03CE2 B9 F4 01 00 00 mov ecx,1F4h 00A03CE7 8D B5 28 F8 FF FF lea esi,[x] 00A03CED 8B FC mov edi,esp 00A03CEF F3 A5 rep movs dword ptr es:[edi],dword ptr [esi] 00A03CF1 6A 01 push 1 00A03CF3 E8 C6 D3 FF FF call _varfun (0A010BEh) 00A03CF8 81 C4 D4 07 00 00 add esp,7D4h #include<stdio.h> #include<stdarg.h> void varfun(int i, ...); int main() { struct eddy { int x[500]; } x = { 0 }; varfun(1, 2, 3, 4, 5, 6); varfun(1, x); return 0; } void varfun(int n_args, ...) { va_list ap; unsigned long *p; unsigned char *p1; unsigned int nargs; va_start(ap, n_args); p = (long *)(ap - _INTSIZEOF(int) - _INTSIZEOF(&varfun)); p1 = (char *)*p; if (*p1 == 0x83) // short add sp,x { nargs = p1[2] / sizeof(int); } else { nargs = *(unsigned long *)(p1+2) / sizeof(int); } printf("%d/n", nargs); va_end(ap); }


Leer un puntero a punteros desde EBP.

#define getReturnAddresses() void ** puEBP = NULL; __asm { mov puEBP, ebp };

Uso

getReturnAddresses(); int argumentCount = *((unsigned char*)puEBP[1] + 2) / sizeof(void*) ; printf("CalledFrom: 0x%08X Argument Count: %i/n", puEBP[1], argumentCount);

No es portátil, pero lo he usado en un desvío x86 C ++ del método __cdecl que llevó un número variable de argumentos a cierto éxito.

Es posible que deba ajustar la parte -1 dependiendo de su pila / argumentos.

No se me ocurrió este método. Sospecho que lo he encontrado en los foros de la UC en algún momento.

No puedo recomendar el uso de este en el código apropiado, pero si tiene un desvío pirata en un archivo x86 con una convención de llamadas __cdecl con 1 argumento y el resto son ... argumentos variables, podría funcionar. (Win32)

Ejemplo de convención del método de desvío.

void __cdecl hook_ofSomeKind_va_list(void* self, unsigned char first, ...)

Prueba: captura de pantalla que muestra la salida de la consola junto a x32dbg en el proceso de destino con un desvío aplicado


No puedes. Algo más tiene que decirle (por ejemplo, para printf, está implícito por el número de descriptores de formato% en la cadena de formato)


No puedes. Tienes que gestionar para que la persona que llama indique el número de argumentos de alguna manera. Usted puede:

  • Pase el número de argumentos como la primera variable
  • Requerir que el último argumento variable sea nulo, cero o lo que sea
  • Haga que el primer argumento describa lo que se espera (por ejemplo, la cadena de formato printf dicta qué argumentos deben seguir)

No puedes. varargs no están diseñados para hacer esto posible. Necesita implementar algún otro mecanismo para decirle a la función cuántos argumentos hay. Una opción común es pasar un argumento centinela al final de la lista de parámetros, por ejemplo:

varfun(1, 2, 3, 4, 5, 6, -1);

Otra es pasar la cuenta al principio:

varfun(6, 1, 2, 3, 4, 5, 6);

Esto es más limpio, pero no tan seguro, ya que es más fácil hacer un recuento incorrecto u olvidarse de actualizarlo que recordar y mantener el centinela al final.

Depende de usted cómo hacerlo (considere el modelo de printf, en el que la cadena de formato determina cuántos y qué tipo de argumentos hay).


Puedes dejar que el preprocesador te ayude a hacer trampa con esta estrategia, robada y modificada por otra respuesta :

#include <stdio.h> #include <stdarg.h> #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,_64,_65,_66,_67,_68,_69,_70, / _71,_72,_73,_74,_75,_76,_77,_78,_79,_80, / _81,_82,_83,_84,_85,_86,_87,_88,_89,_90, / _91,_92,_93,_94,_95,_96,_97,_98,_99,_100, / _101,_102,_103,_104,_105,_106,_107,_108,_109,_110, / _111,_112,_113,_114,_115,_116,_117,_118,_119,_120, / _121,_122,_123,_124,_125,_126,_127,N,...) N #define PP_RSEQ_N() / 127,126,125,124,123,122,121,120, / 119,118,117,116,115,114,113,112,111,110, / 109,108,107,106,105,104,103,102,101,100, / 99,98,97,96,95,94,93,92,91,90, / 89,88,87,86,85,84,83,82,81,80, / 79,78,77,76,75,74,73,72,71,70, / 69,68,67,66,65,64,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 void _variad(size_t argc, ...); #define variad(...) _variad(PP_NARG(__VA_ARGS__), __VA_ARGS__) void _variad(size_t argc, ...) { va_list ap; va_start(ap, argc); for (int i = 0; i < argc; i++) { printf("%d ", va_arg(ap, int)); } printf("/n"); va_end(ap); } int main(int argc, char* argv[]) { variad(2, 4, 6, 8, 10); return 0; }

Hay algunos trucos inteligentes aquí.

1) En lugar de llamar directamente a la función variadic, está llamando a una macro que cuenta los argumentos y pasa el conteo de argumentos como el primer argumento a la función. El resultado final del preprocesador en main se ve así:

_variad(5, 2, 4, 6, 8, 10);

2) PP_NARG es una macro inteligente para contar argumentos.

El caballo de batalla aquí es PP_ARG_N . Devuelve su argumento 128, ignorando los primeros 127 argumentos (nombrados arbitrariamente _1 _2 _3 etc.), nombrando el argumento 128 N y definiendo el resultado de la macro como N

PP_NARG invoca PP_ARG_N con __VA_ARGS__ concatenado con PP_RSEQ_N , una secuencia de números invertida que cuenta desde 127 hasta 0.

Si no proporciona argumentos, el valor 128 de PP_RSEQ_N es 0. Si pasa un argumento a PP_NARG , ese argumento se pasará a PP_ARG_N como _1 ; _2 será 127, y el PP_ARG_N argumento para PP_ARG_N será 1. Por lo tanto, cada argumento en __VA_ARGS__ golpea a PP_RSEQ_N más de uno, dejando la respuesta correcta en la 128ª posición.

(Al parecer, 127 argumentos es lo máximo que permite C ).


Si tiene un compilador compatible con C99 (incluido el preprocesador), puede sortear este problema declarando una macro que calcula el número de argumentos para usted. Hacer esto usted mismo es un poco complicado, puede usar P99_VA_ARGS del paquete de macros P99 para lograr esto.


También puede usar un valor significativo que indique el final de los argumentos. Como un 0 o -1. O un tamaño de letra máximo como 0xFFFF para un ushort .

De lo contrario, debe mencionar el recuento por adelantado o hacerlo deducible de otro argumento ( format para las funciones de tipo printf() ) .