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:
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.