$ gcc -Wall -Werror -x c - << EOF
void f(int x[static 1]){}int main(){f(0);}
EOF
<stdin>:1:37: error: null passed to a
callee that requires a non-null argument
[-Werror,-Wnonnull]
1 | void f(int x[static 1]){}int main(){f(0);}
| ^ ~
<stdin>:1:12: note: callee declares array
parameter as static here
1 | void f(int x[static 1]){}int main(){f(0);}
| ^~~~~~~~~~~
1 error generated.
It can be done, though it usually isn't.Yes.
#include <stdio.h>
#if __has_include(<stdcountof.h>)
#include <stdcountof.h>
#else
#define countof(a) (sizeof (a) / sizeof *(a))
#endif
void
foo(int n, int a[static 1][n])
{
printf("sizeof *a: %zu\n", sizeof *a);
printf("countof *a: %zu\n", countof(*a));
}
int
main(int argc, char *argv[])
{
int array[argc];
foo(countof(array), &array);
return 0;
}
$ ./foo
sizeof *a: 4
countof *a: 1
$ ./foo 2 3
sizeof *a: 12
countof *a: 3
Tested using Apple clang 21.0.0 and gcc 15.2.0.The syntax for using passed VM arrays is stilted; you're operating on a pointer to an array, which can get confusing and is error prone. Because of the semantics for array passing and need for backward compatibility it's too easy to get it wrong without the compiler catching mistakes and complaining. Though, the C2y _Countof operator is required to error when used on a non-array, so using _Countof(a) instead of _Countof(*a) will fail. (GCC and clang also have warning diagnostics that work for the fallback countof macro.) And there's no way (or no easy way?) to ask compilers to inject automatic bounds checking when operating on arrays, at least outside non-production debugging modes like ASan.
But C is getting there, slowly.
His mistake was making _all_ reference taking functions also accept null. In Rust functions opt into None | Some
This comes up with C# which must have default(T) so references default to null. In Rust there is no general default(T) that must always resolve