Is defining a function this way legal or helpful in any way?
void f(int arr[ARR_SIZE])
It's legal (assuming that ARR_SIZE is a positive integral type), and is perhaps a useful annotation, although confusing as it seems to make a false promise. On balance I wouldn't use it.
It doesn't mean that arr is an array of that size: arr is still an int* (due to pointer decay) and all size information is lost.
Far better then to write
void f(int* arr, size_t n)
with f(arr, ARR_SIZE) at the calling site, or f(arr, sizeof(arr)/sizeof(arr[0])) if the non-decayed type of arr is available.
I see one place where passing the (minimum) size can be useful:
void bar(int myArray[static 10]){...}
This tells the compiler that it should assume that the array passed to bar has at least 10 elements and can emit a warning if it is not the case:
int a[9];
bar(a);
returns:
warning: array argument is too small; contains 9 elements, callee requires at least 10 [-Warray-bounds]
bar(a);
^ ~
Legal - yes. Helpful? Not really. Look at this:
#define ARR_SIZE 4
int arr[ARR_SIZE], arr2[345];
f(arr); //works
f(arr2); //also works, compiler doesn't care about what size you specified in the []
This means that you still need to pass the size as a separate parameter:
void f2(int arr[ARR_SIZE], int size);
You can then call this function like this:
f2(arr, ARR_SIZE); //works
f2(arr2, 345); //works
So, don't use this syntax. The recommended prototypes are:
int f(int arr[], int size);
int f(int* arr, int size);
In
void f(int arr[ARR_SIZE]);, ARR_SIZE is practically as good as a comment except the compiler will also verify that ARR_SIZE is either empty or a positive (>=0) integer constant.
Then it's 100% equivalent to void f(int *arr);.
C11 has void f(int arr[static ARR_SIZE]); where you can effectively require that the function only be passed pointers to the first element of arrays that have at least ARR_SIZE members (where ARR_SIZE must be a positive integer constant). E.g., void take_nonnull(int arr[static 1]); or void take_at_least2(int arr[static 2]);. Compilers may or may not issue diagnostics about subsequent calls to f that violate such a requirement (clang routinely does, gcc doesn't).
Yes, but ARR_SIZE must be defined at compile time, like this:
#define ARR_SIZE 3
void f(int arr[ARR_SIZE]){}
int *arr.