IIRC, this is my first on-topic post in comp.lang.c group.
As they say, nobody is perfect.
// pedant_2d.c
int bar(const int a[5][42])
{
return a[0][0];
}
int foo(int x)
{
int a[5][42];
a[0][0] = 1;
return bar(a);
}
// end of pedant_2d.c
$ gcc -std=c17 -pedantic -c pedant_2d.c
pedant_2d.c: In function 'foo':
pedant_2d.c:10:14: warning: invalid use of pointers to arrays with
different qualifiers in ISO C before C23 [-Wpedantic] 10 | return
bar(a); | ^
What does it mean ?
Michael S <already5chosen@yahoo.com> writes:
IIRC, this is my first on-topic post in comp.lang.c group.
As they say, nobody is perfect.
// pedant_2d.c
int bar(const int a[5][42])
{
return a[0][0];
}
int foo(int x)
{
int a[5][42];
a[0][0] = 1;
return bar(a);
}
// end of pedant_2d.c
$ gcc -std=c17 -pedantic -c pedant_2d.c
pedant_2d.c: In function 'foo':
pedant_2d.c:10:14: warning: invalid use of pointers to arrays with different qualifiers in ISO C before C23 [-Wpedantic] 10 | return
bar(a); | ^
What does it mean ?
This is an incomplete answer. Perhaps someone else can fill in
some more details.
Given the parameter declaration `const int a[5][42]`, a is of
course a pointer, not an array. Specifically, it's of type `constint(*)[42])`, or "pointer to array 42 of const int".
(The 5 is quietly ignored.)
The argument `a` in the call (it might have been clearer to use
distinct names) is of type `int[5][42]`, or "array 5 of array
42 of int". In the call, as in most contexts, it decays to
`int (*)[42]`, or "pointer to array 42 of int".
The problem is that the types "pointer to array N of int" and
"pointer to array N of const int" are distinct and are not assignment-compatible.
This seems to be a case where forbidding assignment does not promote
safety. Assigning a `const int*` value to an `int*` object, if
it were allowed, would permit bypassing const correctness, such as
quietly permitting an attempt to assign a value to a const object.
But prior to C23, the rules were a bit more strict than they need
to be.
A simple example:
int main(void) {
int (*x)[10];
const int (*y)[10];
x = y; // discards "const"
y = x;
}
The first assignment is a constraint violation in all versions of
standard C because it discards the "const" qualifier. The second
gets the "before C23" diagnostic with gcc. (clang doesn't
complain about it with either "-pedantic-errors -std=c17" or "-pedantic-errors -std=c23".)
I'm actually not sure what specific changes were made in C23 in
this area. I've compared the "Simple assignment" sections of C17
and C23 (drafts), and the only significant changes were to allow for
values of type nullptr_t.
IMHO, if the standard really says that then every reasonable compiler
shall ignore the Standard and follow practicality.
What does it mean ?
On Wed, 08 Apr 2026 15:57:05 -0700
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
Michael S <already5chosen@yahoo.com> writes:
IIRC, this is my first on-topic post in comp.lang.c group.
As they say, nobody is perfect.
// pedant_2d.c
int bar(const int a[5][42])
{
return a[0][0];
}
int foo(int x)
{
int a[5][42];
a[0][0] = 1;
return bar(a);
}
// end of pedant_2d.c
$ gcc -std=c17 -pedantic -c pedant_2d.c
pedant_2d.c: In function 'foo':
pedant_2d.c:10:14: warning: invalid use of pointers to arrays with
different qualifiers in ISO C before C23 [-Wpedantic] 10 | return
bar(a); | ^
What does it mean ?
This is an incomplete answer. Perhaps someone else can fill in
some more details.
Given the parameter declaration `const int a[5][42]`, a is of
course a pointer, not an array. Specifically, it's of type
`constint(*)[42])`, or "pointer to array 42 of const int".
(The 5 is quietly ignored.)
The argument `a` in the call (it might have been clearer to use
distinct names) is of type `int[5][42]`, or "array 5 of array
42 of int". In the call, as in most contexts, it decays to
`int (*)[42]`, or "pointer to array 42 of int".
The problem is that the types "pointer to array N of int" and
"pointer to array N of const int" are distinct and are not
assignment-compatible.
int bar(const int a[42])
{
return a[0];
}
int foo(int x)
{
int a[42];
a[0] = 1;
return bar(a);
}
That, of course, compile with no wraning.
So, 'pointer to int' is, according to gcc, assignment-compatible (on
the right side) with 'pointer to const int', but in case of pointers to arrays it is not the same?
IMHO, if the standard really says that then every reasonable compiler
shall ignore the Standard and follow practicality.
On Wed 4/8/2026 3:21 PM, Michael S wrote:
What does it mean ?
I already mentioned this issue here not so long ago.
Again, an old puzzle about C const-correctness rules goes as follows:
Is the following initialization
T t;
const T *pt = &t;
valid for all complete object types `T`?
And the answer is "no". The above initialization is not valid if `T`
is an array type. E.g. given
typedef int T[10];
the above initialization contains a constraint violation. Your
original example with 2D array is actually exactly the same thing,
once you take into account function argument type adjustment.
This strange behavior is prescribed by
6.7.3 Type qualifiers
9 If the specification of an array type includes any type
qualifiers, the element type is so qualified, not the array type.
(quoted from C11)
So, the fact that the `const` qualifier applied to array type "falls through" to individual array elements is what prevents this
initialization from working. There's simply no provision in other
rules of the language (re: assignment constraints) that would permit initialization of "pointer to an array of non-const elements" with a "pointer to an array of const elements".
C23 changed the above to the following:
6.7.4 Type qualifiers
6.7.4.1 General
10 If the specification of an array type includes any type
qualifiers, both the array and the element type are so-qualified.
I.e. now const-qualification applies not only to the elements, but
also to the entire array type as well. With this change in place the
above initialization becomes valid. It now falls under the "usual" const-correctness rules. In C23 arrays are no longer special in such contexts.
On Wed 4/8/2026 3:21 PM, Michael S wrote:
What does it mean ?
I already mentioned this issue here not so long ago.
Again, an old puzzle about C const-correctness rules goes as follows:
ÿ Is the following initialization
ÿÿÿ T t;
ÿÿÿ const T *pt = &t;
ÿ valid for all complete object types `T`?
And the answer is "no". The above initialization is not valid if `T` is
an array type. E.g. given
ÿ typedef int T[10];
the above initialization contains a constraint violation. Your original example with 2D array is actually exactly the same thing, once you take
into account function argument type adjustment.
This strange behavior is prescribed by
ÿ 6.7.3 Type qualifiers
ÿ 9 If the specification of an array type includes any type qualifiers,
the element type is so qualified, not the array type.
(quoted from C11)
So, the fact that the `const` qualifier applied to array type "falls through" to individual array elements is what prevents this
initialization from working. There's simply no provision in other rules
of the language (re: assignment constraints) that would permit initialization of "pointer to an array of non-const elements" with a "pointer to an array of const elements".
C23 changed the above to the following:
ÿ 6.7.4 Type qualifiers
ÿ 6.7.4.1 General
ÿ 10 If the specification of an array type includes any type
qualifiers, both the array and the element type are so-qualified.
I.e. now const-qualification applies not only to the elements, but also
to the entire array type as well. With this change in place the above initialization becomes valid. It now falls under the "usual" const- correctness rules. In C23 arrays are no longer special in such contexts.
On 4/8/2026 8:34 PM, Andrey Tarasevich wrote:
On Wed 4/8/2026 3:21 PM, Michael S wrote:
What does it mean ?
I already mentioned this issue here not so long ago.
Again, an old puzzle about C const-correctness rules goes as
follows:
? Is the following initialization
??? T t;
??? const T *pt = &t;
? valid for all complete object types `T`?
And the answer is "no". The above initialization is not valid if
`T` is an array type. E.g. given
? typedef int T[10];
the above initialization contains a constraint violation. Your
original example with 2D array is actually exactly the same thing,
once you take into account function argument type adjustment.
This strange behavior is prescribed by
? 6.7.3 Type qualifiers
? 9 If the specification of an array type includes any type
qualifiers, the element type is so qualified, not the array type.
(quoted from C11)
So, the fact that the `const` qualifier applied to array type
"falls through" to individual array elements is what prevents this initialization from working. There's simply no provision in other
rules of the language (re: assignment constraints) that would
permit initialization of "pointer to an array of non-const
elements" with a "pointer to an array of const elements".
C23 changed the above to the following:
? 6.7.4 Type qualifiers
? 6.7.4.1 General
? 10 If the specification of an array type includes any type
qualifiers, both the array and the element type are so-qualified.
I.e. now const-qualification applies not only to the elements, but
also to the entire array type as well. With this change in place
the above initialization becomes valid. It now falls under the
"usual" const- correctness rules. In C23 arrays are no longer
special in such contexts.
self pointers for an api type const* const ptr? ;^)
On Thu, 9 Apr 2026 02:38:56 -0700
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> wrote:
On 4/8/2026 8:34 PM, Andrey Tarasevich wrote:
On Wed 4/8/2026 3:21 PM, Michael S wrote:
What does it mean ?
I already mentioned this issue here not so long ago.
Again, an old puzzle about C const-correctness rules goes as
follows:
ÿ Is the following initialization
ÿÿÿ T t;
ÿÿÿ const T *pt = &t;
ÿ valid for all complete object types `T`?
And the answer is "no". The above initialization is not valid if
`T` is an array type. E.g. given
ÿ typedef int T[10];
the above initialization contains a constraint violation. Your
original example with 2D array is actually exactly the same thing,
once you take into account function argument type adjustment.
This strange behavior is prescribed by
ÿ 6.7.3 Type qualifiers
ÿ 9 If the specification of an array type includes any type
qualifiers, the element type is so qualified, not the array type.
(quoted from C11)
So, the fact that the `const` qualifier applied to array type
"falls through" to individual array elements is what prevents this
initialization from working. There's simply no provision in other
rules of the language (re: assignment constraints) that would
permit initialization of "pointer to an array of non-const
elements" with a "pointer to an array of const elements".
C23 changed the above to the following:
ÿ 6.7.4 Type qualifiers
ÿ 6.7.4.1 General
ÿ 10 If the specification of an array type includes any type
qualifiers, both the array and the element type are so-qualified.
I.e. now const-qualification applies not only to the elements, but
also to the entire array type as well. With this change in place
the above initialization becomes valid. It now falls under the
"usual" const- correctness rules. In C23 arrays are no longer
special in such contexts.
self pointers for an api type const* const ptr? ;^)
Are you able to decipher your own posts 1 hour later?
struct foo const* const ?
On Thu 4/9/2026 1:09 PM, Chris M. Thomasson wrote:
struct foo const* const ?
Again, the ability to implicitly convert `T **` to `const T* const*`
seems to be related to the above array pointer conversion issue (at
least superficially). In C++ both conversions are supported as
standard (i.e. implicit) conversions. In "classic" C neither is,
which is a bit annoying.
C23 resolved the array issue. But the `T ** -> const T* const*`
conversion is still unsupported as an implicit conversion even in C23.
| Sysop: | Tetrazocine |
|---|---|
| Location: | Melbourne, VIC, Australia |
| Users: | 14 |
| Nodes: | 8 (0 / 8) |
| Uptime: | 93:59:25 |
| Calls: | 211 |
| Files: | 21,502 |
| Messages: | 82,381 |