Reputation: 17284
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));
}
Upvotes: 3
Views: 791
Reputation: 881113
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:
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).
}
Upvotes: 21
Reputation: 169533
Let's look at the expansion of the sample invocation sum(1, 2, 3)
of the macro
#define sum(...) \
_sum(sizeof((int []){ __VA_ARGS__ }) / sizeof(int), (int []){ __VA_ARGS__ })
The ...
mean it's a variadic macro, ie it takes any number of comma-seperated arguments. On expansion, the special preprocessor token __VA_ARGS__
will be replaced with these arguments, ie
(int []){ __VA_ARGS__ }
expands to
(int []){ 1, 2, 3 }
This is a compound literal: C99 allows to create objects with automatic storage duration on-the-fly via such a typed initialization list.
It's important that the size of the array will be inferred: It won't have incomplete type int []
but will be of type int [3]
, ie
sizeof((int []){ 1, 2, 3 }) = sizeof(int [3]) = 3 * sizeof(int)
To get the number of elements, divide by sizeof(int)
.
The macro invocation sum(1, 2, 3)
is therefore equivalent to the C90 code
int tmp[3] = { 1, 2, 3 };
_sum(3, tmp);
Upvotes: 4
Reputation: 19749
The preprocessor here uses variable number of arguments variadic macro. Rest it simply creates an array from argument list and manipulates it
Upvotes: 0
Reputation: 31781
Given an integar array, it will sum up all of its elements and return that value.
Upvotes: 0
Reputation: 5919
In this code the sum
macro converts the sum(1,2,3)
call in main into a call to _sum
by using sizeof
to calculate the number of elements sum
is called with. The size of an int
array with three values is going to be 3 * sizeof(int)
, so dividing by sizeof(int)
yields three again.
Upvotes: 0