Ayúdame a entender este pequeño fragmento de código

Entiendo que este código calcula la sum de los argumentos de una variable, sin embargo, no entiendo cómo funciona. A mi me parece muy abstracto. ¿Alguien puede explicar cómo funciona lo siguiente?

¡Gracias!

#include  #define sum(...) \ _sum(sizeof((int []){ __VA_ARGS__ }) / sizeof(int), (int []){ __VA_ARGS__ }) int _sum(size_t count, int values[]) { int s = 0; while(count--) s += values[count]; return s; } int main(void) { printf("%i", sum(1, 2, 3)); } 

Con la macro preprocesador.

 #define sum(...) \ _sum(sizeof((int []){ __VA_ARGS__ }) / sizeof(int), (int []){ __VA_ARGS__ }) 

al ser llamado con sum(1,2,3) , la línea se traduce (una simple sustitución de cadena, reemplazando "__VA_ARGS__" con "1,2,3" ) en:

 _sum(sizeof((int []){1,2,3}) / sizeof(int), (int []){1,2,3}) 

que es una llamada a la función a _sum() pasando dos cosas:

  • el número de enteros en la matriz {1,2,3} que es 3 (esto se obtiene al dividir el tamaño de la matriz de tres enteros por el tamaño de un solo entero).
  • el puntero a la matriz en sí (o una matriz totalmente diferente que contiene los mismos valores, dependiendo de qué tan inteligente sea su comstackdor).

Todo lo que hace la función _sum() es agregar cada uno de los enteros a s (que inicialmente es cero) hasta que se agote el conteo.


Esa primera bala arriba tiene una explicación. Cuando tienes una matriz de N elementos definidos de la siguiente manera:

 tType x[22]; 

el tamaño de la matriz es sizeof(x) , el tamaño de todos los elementos. El tamaño de un solo elemento de esa matriz es sizeof(x[0]) , el tamaño del primer elemento, aunque a menudo prefiero la variante sizeof(*x) .

Por lo tanto, para contar el número de elementos, simplemente divida el tamaño total por el tamaño de un elemento, utilizando uno de los siguientes:

 sizeof(x) / sizeof(x[0]) sizeof(x) / sizeof(*x) 

Y, dado que ha solicitado un análisis detallado del código, aquí vamos:

 // Needed for printf(). #include  // Macro to convert sum(n1,n2,...,nN) to _sum(N,n1,n2,...,nN). // This calculates the length of the array by dividing its size by the size // of an int and passes both the length and array through to the new // function. // __VA_ARGS__ is replaced with the entire marcro argument list, '1,2,3' in // this case. #define sum(...) \ _sum(sizeof((int []){ __VA_ARGS__ }) / sizeof(int), (int []){ __VA_ARGS__ }) // Function to take size and pointer to int array, and return sum. int _sum (size_t count, int values[]) { int s = 0; // Initial sum of zero. while(count--) // Until elements exhausted (count down). s += values[count]; // Add each array element to accumulator. return s; // Return sum. } int main (void) { printf ("%i", sum(1, 2, 3)); // Test it with 1, 2 and 3 (should print 6). } 

Veamos la expansión de la sum(1, 2, 3) invocación de muestra sum(1, 2, 3) de la macro

 #define sum(...) \ _sum(sizeof((int []){ __VA_ARGS__ }) / sizeof(int), (int []){ __VA_ARGS__ }) 

La ... significa que es una macro variada, es decir, toma cualquier número de argumentos separados por comas. En la expansión, el token de preprocesador especial __VA_ARGS__ se reemplazará con estos argumentos, es decir,

 (int []){ __VA_ARGS__ } 

se expande a

 (int []){ 1, 2, 3 } 

Este es un literal compuesto: C99 permite crear objetos con una duración de almacenamiento automática sobre la marcha a través de una lista de inicialización de este tipo.

Es importante que se infiera el tamaño de la matriz: no tendrá el tipo int [] incompleto int [] pero será del tipo int [3] , es decir

 sizeof((int []){ 1, 2, 3 }) = sizeof(int [3]) = 3 * sizeof(int) 

Para obtener el número de elementos, divida por sizeof(int) .

La sum(1, 2, 3) invocación de macro sum(1, 2, 3) es, por lo tanto, equivalente al código C90.

 int tmp[3] = { 1, 2, 3 }; _sum(3, tmp); 

En este código, la macro de sum convierte la sum(1,2,3) llamada principal en una llamada a _sum utilizando sizeof para calcular el número de elementos con los que se llama sum . El tamaño de una matriz int con tres valores será 3 * sizeof(int) , por lo que al dividir por sizeof(int) obtienen tres de nuevo.

Dada una matriz integar, resumirá todos sus elementos y devolverá ese valor.

El preprocesador aquí usa variable variable de argumentos variable macro . Descansa, simplemente crea una matriz de la lista de argumentos y la manipula.