Someone made an argument saying that in modern C, we should always pass arrays to functions through an array pointer, since array pointers have strong typing. Example:
OP describes a function func() that has the following signature.
void func(size_t n, const int (*arr)[n])
OP wants to call it passing various arrays
#define SZ(a) (sizeof(a)/sizeof(a[0]))
int array1[3];
func(SZ(array1), &array1); // problem
const int array2[3] = {1, 2, 3};
func(SZ(array2), &array2);
How do I apply const correctness to array pointers passed as parameters?
With C11, use _Generic to do the casting as needed. The cast only occurs when the input is of the acceptable non-const type, thus maintaining type safety. This is "how" to do it. OP may consider it "bloated" as it is akin to this. This approach simplifies the macro/function call to only 1 parameter.
void func(size_t n, const int (*arr)[n]) {
printf("sz:%zu (*arr)[0]:%d\n", n, (*arr)[0]);
}
#define funcCC(x) func(sizeof(*x)/sizeof((*x)[0]), \
_Generic(x, \
const int(*)[sizeof(*x)/sizeof((*x)[0])] : x, \
int(*)[sizeof(*x)/sizeof((*x)[0])] : (const int(*)[sizeof(*x)/sizeof((*x)[0])])x \
))
int main(void) {
#define SZ(a) (sizeof(a)/sizeof(a[0]))
int array1[3];
array1[0] = 42;
// func(SZ(array1), &array1);
const int array2[4] = {1, 2, 3, 4};
func(SZ(array2), &array2);
// Notice only 1 parameter to the macro/function call
funcCC(&array1);
funcCC(&array2);
return 0;
}
Output
sz:4 (*arr)[0]:1
sz:3 (*arr)[0]:42
sz:4 (*arr)[0]:1
Alternatively code could use
#define funcCC2(x) func(sizeof(x)/sizeof((x)[0]), \
_Generic(&x, \
const int(*)[sizeof(x)/sizeof((x)[0])] : &x, \
int(*)[sizeof(x)/sizeof((x)[0])] : (const int(*)[sizeof(x)/sizeof((x)[0])])&x \
))
funcCC2(array1);
funcCC2(array2);