una todas tipos retorno parametros llamar las funciones funcion ejemplos con como c

todas - tipos de funciones en c



Llamar dinámicamente a una función C con un argumento varargs (10)

Estoy programando en C contra una biblioteca de terceros (en HP / Mercury Loadrunner) que permite una lista de argumentos de tamaño variable estilo varargs para una de sus funciones. Quiero llamar a esta función, pero no sé desde el principio cuántos argumentos tendré.

Hay una función hecha por uno de mis predecesores que sirve algo, pero el problema aquí es que esta función asume el peor de los casos (más de 3000 argumentos) y códigos de mano para eso.

Para iluminar, aquí está el (principio de) el código. La función que llamamos es web_submit_data() . HTTP publicará un conjunto de datos de formulario. Esta implementación se produjo cuando se trata de formularios generados dinámicamente con un número arbitrario de campos. (Limpiar un poco del original, que codificó manualmente los índices a mano también ...)

web_submit_data_buffer_gazillion_items( const char *bufferName, const char *bufferValue) { const int size = 129; int i = 0; int j = 11; web_submit_data(&bufferName[i++ * size], //"some form" &bufferName[i++ * size], //"Action=https://blah.blah/form"); &bufferName[i++ * size], //"Method=POST"); &bufferName[i++ * size], //"TargetFrame="); &bufferName[i++ * size], //"RecContentType=text/html"); &bufferName[i++ * size], //"Referer=https://blah.blah/index.html"); &bufferName[i++ * size], //"Snapshot=t1.inf"); &bufferName[i++ * size], //"Mode=HTML"); ITEMDATA, // missing in action: indexes 8 through 10 &bufferName[j * size],&bufferValue[j++ * size], ENDITEM, &bufferName[j * size],&bufferValue[j++ * size], ENDITEM, &bufferName[j * size],&bufferValue[j++ * size], ENDITEM, .. (repeat the last 3 lines ad nauseum) .. &bufferName[j * size],&bufferValue[j++ * size], ENDITEM, &bufferName[j * size]); }

Ahora he encontrado una biblioteca externa que podría funcionar ( http://www.dyncall.org ) pero preferiría no a) ser completamente dependiente del procesador yb) intentar enseñar a Loadrunner sobre la vinculación en fuentes externas.

Editar: la función original usó índices codificados en lugar de usar una variable. Todavía puede volver a eso si resulta demasiado impredecible. Sin embargo, como es poco probable que lo ejecute con un compilador o hardware / sistema operativo diferente, dudo que realmente valga la pena.

Además: no tengo control sobre la implementación de web_submit_data (). Así que solo presionar el problema un nivel no lo va a cortar ...

Otra cosa a tener en cuenta: la especificación para web_submit_data() utiliza una constante llamada LAST para marcar el final de la lista de argumentos. La implementación original no lo usa. Presumiblemente, el callsite hace ...


Escríbelo una vez con el preprocesador y nunca mire hacia atrás.

#define WEB_SUBMIT_BUFFER(name, val) / do { / const int size = 129; / int i = 0; / int j = 11; / web_submit_data(&(name)[i++ * size], / &(name)[i++ * size], / /* etc ad nauseum */ / } while (0)

O bien, si la cantidad de argumentos se fija para cada llamada específica, escriba una secuencia de comandos para generar definiciones de preprocesador para ocultar cuán atroz es esa llamada.

#define WEB_SUBMIT_BUFFER_32(name, val) / do { / const int size = 129; / int i = 0; / int j = 11; / web_submit_data(&(name)[i++ * size], / &(name)[i++ * size], / /* 32 times */ / } while (0) #define WEB_SUBMIT_BUFFER_33(name, val) ... #define WEB_SUBMIT_BUFFER_34(name, val) /* etc */


¿Puedes reestructurar tu código para que esto no sea necesario? Tal vez podrías tomar el buffer entrante y hacerlo más determinista:

struct form_field { char[FIELD_NAME_MAX] name; char[FIELD_VALUE_MAX] val; }; web_submit_data_buffer_gazillion_items( const char *bufferName, const char *bufferValue) { /* loop over bufferName somehow, either with a known size or terminating record, and build an array of form_field records */ //loop { // build array of records } web_submit_data(record_array, array_len); }

Lo siento, esto no podría estar más desarrollado, mi esposa me llamó para el desayuno. :-)


No existe una forma portátil de crear una lista de argumentos para una función de argumento variable en C en tiempo de ejecución. Existen algunos trucos dependientes de la implementación, la biblioteca dyncall que encontraste parece una buena y probablemente más portátil que la mayoría.


Nota: el código ya es dependiente del compilador (aunque quizás no depende del procesador), porque la invocación de web_submit_data asume que las subexpresiones del argumento en una llamada a procedimiento se evalúan de izquierda a derecha, pero el lenguaje C deja la orden de evaluación de argumento no especificado.

Ver para referencia: http://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_value

Entonces, quizás la solución no portátil no empeore las cosas para usted.


Tenga en cuenta que la muestra de código que publicó tiene un comportamiento indefinido: las comas que separan los parámetros de función no son puntos de secuencia (esas comas no son el operador de coma), por lo que modificar j varias veces en la lista de argumentos de llamadas de función da como resultado un comportamiento indefinido.

Esto sin mencionar que el orden de evaluación de los argumentos de llamada de función no está especificado por el estándar, por lo que incluso si hicieras la modificación de i y j usando funciones para evaluar los argumentos (las llamadas de función en sí son puntos de secuencia), serías bastante mucho pasando los indicadores en un orden indeterminado.

Además, no veo cómo web_submit_data() sabe cuántos argumentos se han pasado; no veo un conteo o un argumento de centinela definitivo al final. Pero supongo que su ejemplo puede ser solo eso, un ejemplo que podría no tener detalles completos y precisos. Por otro lado, es problema de web_submit_data() todos modos, ¿verdad?


En CamelBones utilizo libffi para llamar a objc_msgSend (), que es una función varargs. Funciona un placer


Hay dos formas de pasar un número variable de argumentos: a una función que acepta "..." o a una función que acepta va_list.

No puede definir dinámicamente la cantidad de argumentos para la interfaz "...", pero debería poder hacerlo para la lista va_list. Google para va_start, va_end y va_list.


Los argumentos de longitud variable son básicamente solo un puntero a un grupo de datos empaquetados que se pasan a la función requerida. Es responsabilidad de la función llamada interpretar estos datos empaquetados.

La forma segura de hacerlo es utilizar las macros va_list (que n-alexander mencionó); de lo contrario, es posible que tenga problemas con la forma en que se rellenan varios tipos de datos en la memoria.

La forma correcta de diseñar funciones varargs es tener realmente dos versiones, una que acepte el ''...'', que a su vez extrae el va_list y lo pasa a una función que toma una va_list. De esta forma, puede construir dinámicamente los argumentos si lo necesita y, en su lugar, puede llamar a la versión de la función va_list.

La mayoría de las funciones IO estándar tienen versiones varargs: vprintf para printf, vsprintf para sprintf ... se entiende la idea. Vea si su biblioteca implementa una función llamada "vweb_submit_data" o algo por el estilo. Si no lo hacen, envíelos por correo electrónico y dígales que arreglen su biblioteca.

3000 líneas de la misma cosa (incluso si es preprocesador inducido) me hace temblar


Sé que este es un hilo viejo, pero acabo de encontrarlo. La forma correcta de manejar datos de formulario de envío de longitud variable en LoadRunner es usar una solicitud_web_web (). Construya la estructura de pares de nombre | valor para la longitud variable de los argumentos como una cadena y la transfiere como parte de la función.

Registre la llamada única como una consulta web_custom_request () y la estructura de la cadena de argumentos para los pares de nombre | valor se volverá obvia. Simplemente use cualquier función de manejo de cadenas C que desee para construir la cadena en cuestión e inclúyala como parte de la lista de argumentos para web_custom_request ().


Dado que generalmente no es un problema pasar más argumentos a una función que toma argumentos variables de los que la función espera (vea la nota al pie de página n. ° 1), puede hacer algo como lo siguiente:

// you didn''t give a clear specification of what you want/need, so this // example may not be quite what you want as I''ve had to guess at // some of the specifications. Hopefully the comments will make clear // what I may have assumed. // // NOTE: while I have compiled this example, I have not tested it, // so there is a distinct possiblity of bugs (particularly // off-by-one errors). Check me on this stuff, please. // I made these up so I could compile the example #define ITEMDATA ((char const*) NULL) #define ENDITEM ((char const*) 0xffffffff) void web_submit_data_wrapper( const char*bufferName, const char* bufferValue, size_t headerCount, // number of header pointers to pass (8 in your example) size_t itemStartIndex, // index where items start in the buffers (11 in your example) size_t itemCount, // number of items to pass (unspecified in your example) size_t dataSize ) // size of each header or item (129 in your example) { // kMaxVarArgs would be 3000 or a gazillion in your case // size_t const kMaxVarArgs = 20; // I''d prefer to use this in C++ #define kMaxVarArgs (20) typedef char const* char_ptr_t; typedef char_ptr_t char_ptr_array_t[kMaxVarArgs]; char_ptr_array_t varargs = {0}; size_t idx = 0; // build up the array of pararmeters we''ll pass to the variable arg list // first the headers while (headerCount--) { varargs[idx++] = &bufferName[idx * dataSize]; } // mark the end of the header data varargs[idx++] = ITEMDATA; // now the "items" while (itemCount--) { varargs[idx++] = &bufferName[itemStartIndex * dataSize]; varargs[idx++] = &bufferValue[itemStartIndex * dataSize]; varargs[idx++] = ENDITEM; ++itemStartIndex; } // the thing after the last item // (I''m not sure what this is from your example) varargs[idx] = &bufferName[itemStartIndex * dataSize]; // now call the target function - the fact that we''re passing more arguments // than necessary should not matter due to the way VA_ARGS are handled // but see the Footnote in the SO answer for a disclaimer web_submit_data( varargs[0], varargs[1], varargs[2], //... ad nasuem until varargs[kMaxVarArgs-1] ); }

Nota al pie # 1: si piensas cómo funcionan las macros en stdargs.h esto se vuelve claro. Sin embargo, no pretendo que esta técnica cumpla con los estándares. De hecho, en la historia reciente, las respuestas de que publiqué en las que he hecho este descargo de responsabilidad han sido, de hecho, no conformes con los estándares (por lo general, por el siempre vigilante litb ). Entonces use esta técnica bajo su propio riesgo, y verifique, verifique, verifique).