Sorry, I was misremembering the edge case here, which indeed is still around pointer decay:
#include <stdio.h>
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
void p (int* a) {
printf("ARRAY_SIZE of arr = %lu, %lu, %lu\n", ARRAY_SIZE(a), sizeof(a), sizeof((a)[0]));
}
int main () {
int arr [] = {0, 1, 2, 3, 4};
printf("ARRAY_SIZE of arr = %lu, %lu, %lu\n", ARRAY_SIZE(arr), sizeof(arr), sizeof((arr)[0]));
p(arr);
}
prints:
ARRAY_SIZE of arr = 5, 20, 4
ARRAY_SIZE of arr = 2, 8, 4
where in the function, the arr has decayed into a pointer losing the additional info about size (now the size of a pointer 8bytes or 64bits on my host). Which is why you usually get the length of the array before invoking the function and pass it in as additional information, or wrap the complete array in a struct to preserve sizeof info (http://spin.atomicobject.com/2014/03/25/c-single-member-stru...).
ARRAY_SIZE of arr = 5, 20, 4
ARRAY_SIZE of arr = 2, 8, 4
where in the function, the arr has decayed into a pointer losing the additional info about size (now the size of a pointer 8bytes or 64bits on my host). Which is why you usually get the length of the array before invoking the function and pass it in as additional information, or wrap the complete array in a struct to preserve sizeof info (http://spin.atomicobject.com/2014/03/25/c-single-member-stru...).