Path: csiph.com!eternal-september.org!feeder.eternal-september.org!nntp.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c Subject: Re: pedantic gcc and const 2D arrays Date: Mon, 13 Apr 2026 05:40:50 -0700 Organization: A noiseless patient Spider Lines: 91 Message-ID: <864ilf823x.fsf@linuxsc.com> References: <20260409012107.00006dc5@yahoo.com> <10r76oj$1vci$1@dont-email.me> <10r7s3h$7jht$2@dont-email.me> <20260409140602.00007b72@yahoo.com> <10r912i$jtv1$1@dont-email.me> <10rgobr$2o806$1@dont-email.me> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Date: Mon, 13 Apr 2026 12:40:52 +0000 (UTC) Injection-Info: dont-email.me; posting-host="1700fa93b8e58fbb3b86c46e932ae128"; logging-data="3479193"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+PYKVbt25SNb9p1u9LKZ27TepBu/IC6DM=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:7mT4E9qpyzUAd1jTXBxYGI3hQTo= sha1:tvKRPLRtZtJliRvsYgNcy/0trNo= Xref: csiph.com comp.lang.c:397515 Andrey Tarasevich 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).