Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Help me understand this short chunk of code

Tags:

c

I understand this code calculates the sum of the args of a variable, however, I don't understand how it works. It looks really abstract to me. Can someone explain how the below works?

Thanks!

#include <stdio.h>

#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));
}
like image 917
nubela Avatar asked Nov 29 '22 05:11

nubela


1 Answers

With the pre-processor macro

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

being called with sum(1,2,3), the line is translated (a simple string substitution, replacing "__VA_ARGS__" with "1,2,3") into:

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

which is a function call to _sum() passing two things:

  • the number of integers in the array {1,2,3} which is 3 (it gets this by dividing the size of the three-integer array by the size of a single integer).
  • the pointer to the array itself (or a totally different array containing the same values, depending on how smart your compiler is).

All the _sum() function does is add each of the integers to s (which is initially zero) until the count runs out.


That first bullet point above bears some explanation. When you have an array of N elements defined as follows:

tType x[22];

the size of the array is sizeof(x), the size of all elements. The size of a single element of that array is sizeof(x[0]), the size of the first element, although I often prefer the sizeof(*x) variant.

So, to count the number of elements, you simply divide the total size by the size of an element, using one of the following:

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

And, since you've asked for a detailed analysis of the code, here we go:

// Needed for printf().

#include <stdio.h>

// 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).
}
like image 60
paxdiablo Avatar answered Dec 15 '22 05:12

paxdiablo