I'm fully aware that, when passed to a function, an array just decays to a pointer, so you can't use sizeof(x)/sizeof((x)[0])
to work out their size. However, I found out that one can use (&x)[1]-x
, i.e. pointer arithmetic, so, out of curiosity, I tried to make a function that takes two arrays, works out their lengths, and joins them (using malloc
to dynamically allocate a chunk of memory whose size is the sum of their lengths, times the size of an int).
This works:
#define ARR_LEN(a) ((&(a))[1]-(a))
void join (int a[], int b[]) {
printf("%zu %zu", ARR_LEN(a), ARR_LEN(b));
}
int main() {
int a[3] = {0, 1, 2};
int b[5] = {0, 1, 2, 3, 4};
join(a, b);
return 0;
}
It prints 3 5
. However, changing the body of join
to store ARR_LEN(a)
in a local variable n
, even after we print ARR_LEN(a)
the first time:
int n;
printf("%zu %zu", ARR_LEN(a), ARR_LEN(b));
n = ARR_LEN(a);
causes seemingly pseudorandom results such as 18446708891292021383 5
. Weirdest of all, it works fine, printing 3 5
, when n
is global, rather than local. Additionally, then printing the contents of n
gives a different number to the first.
My guess is that, when a
and b
are on the stack, putting n
on there somehow causes the C compiler to get confused about their sizes, although this issue persists when I declare n
as int __attribute__ ((aligned (256)))
to try to force it away from the other two (and any weird caching problems). When I print &a
, &b
and &n
, I get something like:
0x7ffd680a8df8 0x7ffd680a8df0 0x7ffd680a8e00
While, when n
is global, &n
is 0x404200
, since .data
is below the stack. Additionally, when n
is global and I instead, say, put a local variable m = ARR_LEN(b)
, a
gets "corrupted" while ARR_LEN(b)
is again correctly printed.
This works:
No, it does not. You were lucky. As function parameters int a[]
and int *a
mean exactly the same.
&(a)
is giving the address of the local variable a
(and it is a pointer to pointer in this case)(&(a))[1]
- derefences the pointer to pointer (&(a))
at index 1
which is undefined behaviour.There is no way to take the size of the passed array, and no "hacky tricks" exist.