Ya que hemos estudiado las MACROS en Arduino, ahora vamos a aplicar algo interesante para desarrollar de una forma más extensible nuestros programas.

Si hemos programado alguna vez con otros lenguajes; especialmente en C; podremos observar que se nos permite manejar funciones con un número de parámetros de entrada variables.

Por ejemplo, podríamos construir una función concatenación de Strings para añadir palabras una detrás de otra, hasta crear una frase extendida.

int main ( int argc, char *argv[] ) {
     
     return 0;
}

Donde argc es el contador de argumentos de entrada y argv es cada uno de los argumentos que se acceden como si de un vector se tratara.
También se puede crear la función de la siguiente manera:

int main ( int argc, char **argv) {
     
     return 0;
}

Pero en Arduino no es tan sencillo acceder a estas pautas de programación. Por ello utilizaremos tres puntos suspensivos “…”, para identificar que nuestros parámetros de entrada en esa función serán variables. A esto se le llama variadic arguments in C++.

Pero antes que nada, vamos a gestionar los accesos a los parametros para identificar el número de parámetros que integramos con los parametros en sí. Visto lo relacionado con MACROS del post anterior, ahora realizaremos una manipulación de estos componentes para desarrollar nuestras funciones con parámetros variables desde variadic MACROS.

#define NUMARGS(...)  (sizeof((int[]){__VA_ARGS__})/sizeof(int))

void setup() {
  Serial.begin(9600);
}

void loop() {

  Serial.println(NUMARGS(1,2,3,4,5,6,7));
  
}

Lo que vamos a determinar con este pequeño programa es el manejo de una palabra reservada __VA_ARGS__ dentro de las MACROS para poder acceder a los parámetros que recopila la función con “…” de variadic MACROS.

Y de una forma más limpia realizaremos lo siguiente, para manejar mejor los datos.

#define NUMARGS(...)  (sizeof((int[]){__VA_ARGS__})/sizeof(int))
#define VARACCESS(...)  (varargs(NUMARGS(__VA_ARGS__), __VA_ARGS__))

void varargs ( int nargs, ... ) {
     Serial.println(nargs);
}

void setup() {
  Serial.begin(9600);
}

void loop() {

  VARACCESS(1,2,3,4,5,6,7);
}

De esta manera ya podemos identificar cuántos parámetros de entrada hay en nuestra función, pero nos falta poder seleccionar cada argumento por separado para poder manipularlo. Para ello utilizaremos la librería <cstdarg.h>

 #include <stdarg.h>

//We use "..." to indicate that we use variadic arguments

#define NUMARGS(...)  (sizeof((int[]){__VA_ARGS__})/sizeof(int))
#define SUM(...)  (sum(NUMARGS(__VA_ARGS__), __VA_ARGS__))

void sum(int numargs, ...) {
    int total = 0;

    //Creating list of arguments
    va_list ap;
    
    //numargs access directly to the number of arguments in function
    Serial.print("sum() called with params:");
    Serial.println( numargs);

    //Initialize vector of arguments
    va_start(ap, numargs);
    while (numargs--)
        total += va_arg(ap, int);
    va_end(ap);

    Serial.println("");
    Serial.println(total);
}

     
void setup() {
  Serial.begin(9600);
  SUM(1,2,3,4);
}

void loop() {
  SUM(1,2,3,4,5,6,7,8,9,10);

  
} 

Como podremos observar, hay que añadir la librería de C <stdarg.h> que es la encargada de gestionar los accesos a los argumentos de entrada de una función.

Dentro de esta librería se encuentran unas funciones muy útiles.

  • va_list –> Objeto vector que crea la lista de acceso a los argumentos.
  • va_start –> Inicialización del vector en una variable va_list
  • va_arg –> Lectura de argumentos
  • va_copy
  • va_end –> Finalización de lectura del vector de argumentos