Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Const correctness for array pointers?

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:

void func (size_t n, int (*arr)[n]);
...

int array [3];
func(3, &array);

This sounded like it could potentially be a good idea to prevent all kinds of type-related and array-out-of-bounds bugs. But then it occurred to me I don't know how to apply const correctness to this.

If I do void func (size_t n, const int (*arr)[n]) then it is const correct. But then I can no longer pass the array, because of incompatible pointer types. int (*)[3] versus const int (*)[3]. The qualifier belongs to the pointed-at data and not to the pointer itself.

An explicit cast in the caller would ruin the whole idea of increased type safety.

How do I apply const correctness to array pointers passed as parameters? Is it at all possible?


EDIT

Just as info, someone said that the idea of passing arrays by pointer like this probably originates from MISRA C++:2008 5-2-12. See for example PRQA's high integrity C++ standard.

like image 318
Lundin Avatar asked Mar 24 '16 11:03

Lundin


People also ask

What is const correctness in C++?

By Alex Allain. The const keyword allows you to specify whether or not a variable is modifiable. You can use const to prevent modifications to variables and const pointers and const references prevent changing the data pointed to (or referenced).

Are arrays const pointers?

The name of the array A is a constant pointer to the first element of the array. So A can be considered a const int*. Since A is a constant pointer, A = NULL would be an illegal statement. Arrays and pointers are synonymous in terms of how they use to access memory.

Can a pointer be const?

A pointer to a const value (sometimes called a pointer to const for short) is a (non-const) pointer that points to a constant value. In the above example, ptr points to a const int . Because the data type being pointed to is const, the value being pointed to can't be changed. We can also make a pointer itself constant.

Can pointer change const value?

const int * is a pointer to an integer constant. That means, the integer value that it is pointing at cannot be changed using that pointer.


2 Answers

There is no way to do it except for the cast. This is significant drawback of the idea to pass arrays in this way.

Here is a similar thread where the C rules are compared to the C++ rules. We could conclude from this comparison that the C rules are not so well designed, because your use case is valid but C doesn't allow the implicit conversion. Another such example is conversion of T ** to T const * const *; this is safe but is not allowed by C.

Note that since n is not a constant expression, then int n, int (*arr)[n] does not have any added type safety compared to int n, int *arr. You still know the length (n), and it is still silent undefined behaviour to access out of bounds, and silent undefined behaviour to pass an array that is not actually length n.

This technique has more value in the case of passing non-VLA arrays , when the compiler must report if you pass a pointer to an array of the wrong length.

like image 116
M.M Avatar answered Oct 07 '22 01:10

M.M


C standard says that (section: §6.7.3/9):

If the specification of an array type includes any type qualifiers, the element type is so- qualified, not the array type.[...]

Therefore, in case of const int (*arr)[n], const is applied to the elements of the array instead of array arr itself. arr is of type pointer to array[n] of const int while you are passing a parameter of type pointer to array[n] of int. Both types are incompatible.

How do I apply const correctness to array pointers passed as parameters? Is it at all possible?

It's not possible. There is no way to do this in standard C without using explicit cast.

But, GCC allow this as an extension:

In GNU C, pointers to arrays with qualifiers work similar to pointers to other qualified types. For example, a value of type int (*)[5] can be used to initialize a variable of type const int (*)[5]. These types are incompatible in ISO C because the const qualifier is formally attached to the element type of the array and not the array itself.

 extern void
 transpose (int N, int M, double out[M][N], const double in[N][M]);
 double x[3][2];
 double y[2][3];
 ...
 transpose(3, 2, y, x); 

Further reading: Pointer to array with const qualifier in C & C++

like image 31
haccks Avatar answered Oct 07 '22 03:10

haccks