Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #397434 > unrolled thread
| Started by | Michael S <already5chosen@yahoo.com> |
|---|---|
| First post | 2026-04-09 01:21 +0300 |
| Last post | 2026-04-27 07:27 -0700 |
| Articles | 14 — 6 participants |
Back to article view | Back to comp.lang.c
pedantic gcc and const 2D arrays Michael S <already5chosen@yahoo.com> - 2026-04-09 01:21 +0300
Re: pedantic gcc and const 2D arrays Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-04-08 15:57 -0700
Re: pedantic gcc and const 2D arrays Michael S <already5chosen@yahoo.com> - 2026-04-09 03:09 +0300
Re: pedantic gcc and const 2D arrays 🇵🇱Jacek Marcin Jaworski🇵🇱 <jmj@energokod.gda.pl> - 2026-04-09 02:33 +0200
Re: pedantic gcc and const 2D arrays Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-04-08 21:42 -0700
Re: pedantic gcc and const 2D arrays Andrey Tarasevich <noone@noone.net> - 2026-04-08 20:34 -0700
Re: pedantic gcc and const 2D arrays Michael S <already5chosen@yahoo.com> - 2026-04-09 11:09 +0300
Re: pedantic gcc and const 2D arrays "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-04-09 02:38 -0700
Re: pedantic gcc and const 2D arrays Michael S <already5chosen@yahoo.com> - 2026-04-09 14:06 +0300
Re: pedantic gcc and const 2D arrays "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-04-09 13:09 -0700
Re: pedantic gcc and const 2D arrays Andrey Tarasevich <noone@noone.net> - 2026-04-12 11:30 -0700
Re: pedantic gcc and const 2D arrays Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-04-13 05:40 -0700
Re: pedantic gcc and const 2D arrays Andrey Tarasevich <noone@noone.net> - 2026-04-26 13:45 -0700
Re: pedantic gcc and const 2D arrays Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-04-27 07:27 -0700
| From | Michael S <already5chosen@yahoo.com> |
|---|---|
| Date | 2026-04-09 01:21 +0300 |
| Subject | pedantic gcc and const 2D arrays |
| Message-ID | <20260409012107.00006dc5@yahoo.com> |
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 ?
[toc] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2026-04-08 15:57 -0700 |
| Message-ID | <87ldex2h8e.fsf@example.invalid> |
| In reply to | #397434 |
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.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Michael S <already5chosen@yahoo.com> |
|---|---|
| Date | 2026-04-09 03:09 +0300 |
| Message-ID | <20260409030937.00000c95@yahoo.com> |
| In reply to | #397435 |
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.
> 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.
>
[toc] | [prev] | [next] | [standalone]
| From | 🇵🇱Jacek Marcin Jaworski🇵🇱 <jmj@energokod.gda.pl> |
|---|---|
| Date | 2026-04-09 02:33 +0200 |
| Message-ID | <4rCdnZTfUe1Kbkv0nZ2dnZfqnPednZ2d@giganews.com> |
| In reply to | #397438 |
W dniu 9.04.2026 o 02:09, Michael S pisze: > IMHO, if the standard really says that then every reasonable compiler > shall ignore the Standard and follow practicality. But if they drop the Standard and made each C lang compiler in different way then: How to write portable code in C lang? -- Jacek Marcin Jaworski, Pruszcz Gd., woj. Pomorskie, Polska 🇵🇱, EU 🇪🇺; tel.: +48-609-170-742, najlepiej w godz.: 5:00-5:55 lub 16:00-17:25; <jmj@energokod.gda.pl>, gpg: 4A541AA7A6E872318B85D7F6A651CC39244B0BFA; Domowa s. WWW: <https://energokod.gda.pl>; Mini Netykieta: <https://energokod.gda.pl/MiniNetykieta.html>; Mailowa Samoobrona: <https://emailselfdefense.fsf.org/pl>. UWAGA: NIE ZACIĄGAJ "UKRYTEGO DŁUGU"! PŁAĆ ZA PROG. FOSS I INFO. INTERNETOWE! CZYTAJ DARMOWY: "17. Raport Totaliztyczny - Patroni Kontra Bankierzy": <https://energokod.gda.pl/raporty-totaliztyczne/17.%20Patroni%20Kontra%20Bankierzy.pdf>
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2026-04-08 21:42 -0700 |
| Message-ID | <86ldewwxqp.fsf@linuxsc.com> |
| In reply to | #397438 |
Michael S <already5chosen@yahoo.com> writes:
> 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?
The analogous case with pointers is not const int * but const int **,
which also fails if given an int **. Andrey Tarasevich gave an
explanation.
> IMHO, if the standard really says that then every reasonable compiler
> shall ignore the Standard and follow practicality.
I think that's an overreaction. This particular problem doesn't come
up very often. When it does, usually it's easy to fix just by writing
a wrapper function and calling that instead:
int bar(const int a[5][42])
{
return a[0][0];
}
int bas(int a[5][42]){
return bar( (const int (*)[42]) a );
}
int foo(int x)
{
int a[5][42];
a[0][0] = 1;
return bas(a);
}
[toc] | [prev] | [next] | [standalone]
| From | Andrey Tarasevich <noone@noone.net> |
|---|---|
| Date | 2026-04-08 20:34 -0700 |
| Message-ID | <10r76oj$1vci$1@dont-email.me> |
| In reply to | #397434 |
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.
--
Best regards,
Andrey
[toc] | [prev] | [next] | [standalone]
| From | Michael S <already5chosen@yahoo.com> |
|---|---|
| Date | 2026-04-09 11:09 +0300 |
| Message-ID | <20260409110924.00000f9f@yahoo.com> |
| In reply to | #397442 |
On Wed, 8 Apr 2026 20:34:43 -0700 Andrey Tarasevich <noone@noone.net> 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. > Thank you.
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> |
|---|---|
| Date | 2026-04-09 02:38 -0700 |
| Message-ID | <10r7s3h$7jht$2@dont-email.me> |
| In reply to | #397442 |
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? ;^)
[toc] | [prev] | [next] | [standalone]
| From | Michael S <already5chosen@yahoo.com> |
|---|---|
| Date | 2026-04-09 14:06 +0300 |
| Message-ID | <20260409140602.00007b72@yahoo.com> |
| In reply to | #397447 |
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?
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> |
|---|---|
| Date | 2026-04-09 13:09 -0700 |
| Message-ID | <10r912i$jtv1$1@dont-email.me> |
| In reply to | #397449 |
On 4/9/2026 4:06 AM, Michael S wrote:
> 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?
>
>
>
;^)
Yes, say a const pointer to a const object?
struct foo const* const ?
Here is some old C code of mine for a test:
/* Interfaces
____________________________________________________________________*/
#include <stddef.h>
struct object_prv_vtable {
int (*fp_destroy) (void* const);
};
struct device_prv_vtable {
int (*fp_read) (void* const, void*, size_t);
int (*fp_write) (void* const, void const*, size_t);
};
struct device_vtable {
struct object_prv_vtable const object;
struct device_prv_vtable const device;
};
struct device {
struct device_vtable const* vtable;
};
#define object_destroy(mp_self) ( \
(mp_self)->vtable->object.fp_destroy((mp_self)) \
)
#define device_read(mp_self, mp_buf, mp_size) ( \
(mp_self)->vtable->device.fp_read((mp_self), (mp_buf), (mp_size)) \
)
#define device_write(mp_self, mp_buf, mp_size) ( \
(mp_self)->vtable->device.fp_write((mp_self), (mp_buf), (mp_size)) \
)
/* Sample Header (usb_drive.h)
____________________________________________________________________*/
#if ! defined(USB_HEADER_H)
#define USB_HEADER_H
extern int usb_drive_create(struct device** const);
#endif
/* Sample Impl (usb_drive.c)
____________________________________________________________________*/
/* #include "usb_drive.c" */
#include <stdio.h>
#include <stdlib.h>
struct usb_drive {
struct device device;
/* whatever */
};
static int usb_drive_object_destroy(void* const);
static int usb_drive_device_read(void* const, void*, size_t);
static int usb_drive_device_write(void* const, void const*, size_t);
static struct device_vtable const g_table = {
{ /* object */
usb_drive_object_destroy
},
{ /* device */
usb_drive_device_read,
usb_drive_device_write
}
};
int usb_drive_create(
struct device** const pself
) {
struct usb_drive* const self = malloc(sizeof(*self));
if (self) {
self->device.vtable = &g_table;
*pself = &self->device;
return 0;
}
return -1;
}
int usb_drive_object_destroy(
void* const self_
) {
struct usb_drive* const self = self_;
printf("usb_drive_object_destroy(%p)\n", (void*)self);
free(self_);
return 0;
}
int usb_drive_device_read(
void* const self_,
void* buf,
size_t size
) {
struct usb_drive* const self = self_;
printf("usb_drive_device_read(%p, %p, %lu)\n",
(void*)self, buf, (unsigned long)size);
return 0;
}
int usb_drive_device_write(
void* const self_,
void const* buf,
size_t size
) {
struct usb_drive* const self = self_;
printf("usb_drive_device_write(%p, %p, %lu)\n",
(void*)self, buf, (unsigned long)size);
return 0;
}
/* Sample Application
____________________________________________________________________*/
void read_write(
struct device* const self
) {
char buf[100];
device_read(self, buf, 50);
device_write(self, buf, 5);
}
int main(void) {
struct device* a_device;
if (! usb_drive_create(&a_device)) {
read_write(a_device);
object_destroy(a_device);
}
return 0;
}
[toc] | [prev] | [next] | [standalone]
| From | Andrey Tarasevich <noone@noone.net> |
|---|---|
| Date | 2026-04-12 11:30 -0700 |
| Message-ID | <10rgobr$2o806$1@dont-email.me> |
| In reply to | #397453 |
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. -- Best regards, Andrey
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2026-04-13 05:40 -0700 |
| Message-ID | <864ilf823x.fsf@linuxsc.com> |
| In reply to | #397511 |
Andrey Tarasevich <noone@noone.net> writes:
> 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.
The circumstances with arrays and with pointers are rather
different. With pointers, one can always convert to a more
const-laden version of a type by using a cast:
int
takes_ppi( int **p ){
return **p;
}
int
takes_ppci( const int **p ){
return **p;
}
int
takes_pcpi( int *const *p ){
return **p;
}
int
takes_pcpci( const int *const *p ){
return **p;
}
int
try_each_pointer_type( int **p ){
int a = takes_ppi( p );
int b = takes_ppci( (const int **) p );
int c = takes_pcpi( p );
int d = takes_pcpci( (const int *const*) p );
return a+b+c+d;
}
Notice in the case of takes_pcpi() that no cast is needed. That's
because the rule that 'X*' may be converted to 'const X*' applies
even when 'X' is a pointer type. Incidentally, the 'takes_ppci()'
case gives a warning under gcc with -Wall -Wextra, so using a cast
is "safe" in the sense that it is possible to get a warning for a
dangerous conversion.
The problem with arrays is that there is no way to convert from an
argument of type 'X*' to type 'const X*' when X is an array type,
because before C23 "const array" types _didn't exist_. Thus there
is no way to satisfy the rules for pointer conversion just by
writing a cast. There is a way around the problem of wanting to
convert to, for example, a 'const int (*)[1]' type, but it's more
cumbersome:
int
takes_pai( int (*p)[1] ){
return (*p)[0];
}
int
takes_paci( const int (*p)[1] ){
return (*p)[0];
}
int
try_each_array_type( int (*p)[1] ){
union { int (*pai)[1]; const int (*paci)[1]; } both = {p};
int a = takes_pai( p );
int b = takes_paci( both.paci );
return a+b;
}
Mixing const-ness and pointer-ness is tricky, or at least
non-obvious. I'm not sure the C decision regarding implicit
conversions when const-ness and pointer-ness are both involved is a
bad choice. Since it doesn't come up very often, and the remedy for
when it does come up is so straightforward, it might be better to
adopt a simple rule, as C has done, than to complicate the language
definition with a more elaborate rule. But arrays are another
kettle of fish altogether, and I'm happy to see the issues around
const arrays are finally getting the attention they deserve (which I
have been advocating for more than 10 years now).
[toc] | [prev] | [next] | [standalone]
| From | Andrey Tarasevich <noone@noone.net> |
|---|---|
| Date | 2026-04-26 13:45 -0700 |
| Message-ID | <10sltgu$1s5u8$1@dont-email.me> |
| In reply to | #397515 |
On Mon 4/13/2026 5:40 AM, Tim Rentsch wrote: > But arrays are another > kettle of fish altogether, and I'm happy to see the issues around > const arrays are finally getting the attention they deserve (which I > have been advocating for more than 10 years now). What I still don't understand is some remaining details about this specific conversion for array pointers, even after C23 changes. Previously I wrote: "[...] now const-qualification applies not only to the elements, but also to the entire array type as well. [...] It now falls under the "usual" const-correctness rules. In C23 arrays are no longer special in such contexts" But on the second thought, this is oversimplifying things. What about remaining rules of type compatibility wrt const-qualification of array elements? Again, when we do something like this: typedef int A[10]; A a; const A *pa = &a; this is equivalent, speaking informally, to int a[10]; const int (const *pa)[10] = &a; i.e. as C23 states, the const-qualification is applied to both the array itself and to its elements. (Yes, I know that the `pa` declaration is formally invalid. This version is intended as a sketch.) So, the `const` that applies to the array itself does indeed fall under the "usual const-correctness rules" - we are just adding `const` in a pointer conversion. Nothing to see here. But what about the `const` on the array elements? It is still there even in C23. Good old C type compatibility rules state that for two arrays types to be compatible their element types have to be compatible. And the latter requires identical qualification. In the above case, since in C23 `const` continues to fall-through to array elements, const-qualification of the element type does not match: one array type has `int` elements, another - `const int` elements. So, why is const A *pa = &a; valid in C23? Am I missing another little change somewhere in C23? -- Best regards, Andrey
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2026-04-27 07:27 -0700 |
| Message-ID | <86qzo01nrx.fsf@linuxsc.com> |
| In reply to | #398009 |
Andrey Tarasevich <noone@noone.net> writes:
> On Mon 4/13/2026 5:40 AM, Tim Rentsch wrote:
>
>> But arrays are another
>> kettle of fish altogether, and I'm happy to see the issues around
>> const arrays are finally getting the attention they deserve (which I
>> have been advocating for more than 10 years now).
>
> What I still don't understand is some remaining details about this
> specific conversion for array pointers, even after C23 changes.
>
> Previously I wrote:
>
> "[...] now const-qualification applies not only to the elements, but
> also to the entire array type as well. [...] It now falls under the
> "usual" const-correctness rules. In C23 arrays are no longer special
> in such contexts"
>
> But on the second thought, this is oversimplifying things. What about
> remaining rules of type compatibility wrt const-qualification of array
> elements?
I think I see where you're going here. Let's see if we can clear
up the seeming contradictions. Forgive me if I meander a bit.
> Again, when we do something like this:
>
> typedef int A[10];
> A a;
> const A *pa = &a;
>
> this is equivalent, speaking informally, to
>
> int a[10];
> const int (const *pa)[10] = &a;
>
> i.e. as C23 states, the const-qualification is applied to both the
> array itself and to its elements. (Yes, I know that the `pa`
> declaration is formally invalid. This version is intended as a
> sketch.)
I'd like to rewrite these two lines, using a slightly different
syntax to help the subsequent explanation:
int [10] a;
int const [10] const *pa = &a;
In this syntax declarations are read right-to-left, with each
'const' applying to what is to its immediate left.
> So, the `const` that applies to the array itself does indeed fall
> under the "usual const-correctness rules" - we are just adding `const`
> in a pointer conversion. Nothing to see here.
>
> But what about the `const` on the array elements? It is still there
> even in C23. Good old C type compatibility rules state that for two
> arrays types to be compatible their element types have to be
> compatible. And the latter requires identical qualification.
To address this question let's change the scenario slightly. First
I want to be able to write a 'struct' type without the keyword, and
also with the rule that keyword-less structs are the same if their
members are the same. Thus, the two declarations
{ int x; } foo = {1};
{ int x; } *pfoo = &foo;
are allowed, because the two keyword-less struct types are in
essence the same type.
Now some observations about the type of foo. If somewhere else
there were a separate declaration for foo (perhaps in a header
file), it could not be written as either
extern { int const x; } foo;
or as
extern { int x; } const foo;
because of type compatibility rules. Of course the point of
considering these alternatives is to reason analogously to array
types, but with the freedom to have the const-ness of the "element"
type be independent of the aggregate type.
Given the previous declaration/definition for foo, let's say at file
scope, we could declare a second variable cfoo -- this time as being
local to a function, and also const-qualified -- like so
{ int x; } const cfoo = foo;
because the "element" type of cfoo matches the element type of foo,
even though the aggregate types are different.
Now we want to ask about the type of cfoo.x. Obviously that type
must be int. But is it? It's kind of yes and no. If we take the
address of cfoo.x, it looks like its type cannot be int, because
this attempt to use it
int *pcfoo_s_x = &cfoo.x; // doesn't work
fails, for the obvious reason that we don't want to be able to
modify a const object by changing the "element" cfoo.x by using the
pointer pcfoo_s_x. So, sort of like arrays, the const-ness of the
outer keyword-less struct "falls through", in a sense, to the type
of the member x.
Let's enlarge the focus a bit. Surely we expect to be able to write
this declaration
{ int x; } const *p_unassignable_foo = &foo;
following the usual rules of address conversion (a pointer of type
X* can be converted to a pointer of type const X*). But wait! We
already agreed that a second declaration of foo with
extern { int x; } const foo;
isn't allowed, because of type incompatibility. So why is it that the
address of foo can be converted to a pointer to an _incompatible_ type
in the assignement to p_unassignable_foo? Of course the simple answer
is that the language allows it. The more satisfying answer is that
the language allows the conversion because it is safe, even though the
pointed-to types are not compatible. The const-ness of the "element"
x is not relevant to the question -- it's safe to assign a X* to a
const X*, and thus it's allowed, with the caveat that to make it work
we have to insist that an assignment like
p_unassignable_foo->x = 17;
be disallowed.
I expect you can run this explanation backwards to the array case,
and see why a pointer to an array can be converted to a pointer to a
C23-const array makes sense, even though there is a level of type
incompatibility involved in the two types involved. The conversion
is safe, and that's why it's allowed; the const-ness of the element
type is just a detail to be considered in deciding how to make the
conversion not violate what we expect for const-qualified types.
> In the above case, since in C23 `const` continues to fall-through to
> array elements, const-qualification of the element type does not
> match: one array type has `int` elements, another - `const int`
> elements. So, why is
>
> const A *pa = &a;
>
> valid in C23? Am I missing another little change somewhere in C23?
The answer is the compatibility of the pointed to types doesn't
matter. The conversion of the pointer type is allowed because it
preserves our expectation for how const-qualified types behave, and
the compability of the pointed-to types was just a red herring.
I'm sorry to take so long to get to the point. My explanation
reflects the thought process that I went through to understand
and then answer your question. I hope it has cleared up how to
understand the new rules for array const-ness.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c
csiph-web