Hi there!

Your example is irrelevant. We're discussing "Foo**"->"const Foo * const *
const" conversion (all-consts).
And your example is about "const Foo*const*", see void foo(const int *const
*p) {}.
Below is the right example (I already posted it, so once again):
"
void subfunc(struct zzz const * const * const arg) {

if (arg != NULL) {
printf("%s", "Done!");
}
}

void func(struct zzz ** arr_of_ptr, unsigned count) {

subfunc((struct zzz const * const * const)arr_of_ptr); // ОК!

*subfunc(arr_of_ptr);* // CLANG: x86-64 clang (trunk) - WARNING!!!
// GCC: x86-64 gcc (trunk) - ERROR!!!
// INTEL: x86-64 icc 2021.10.0 - OK!!!
// MICROSOFT(c++?): x64 msvc v19.latest - OK!!!
// POWER64 GCC trunk - ERROR!!!
// ARM gcc(trunk) - ERROR!!!
// NOTE: based on godbolt.org
}".
And here in green the results of different compilers are shown.
Introducing ''-pedantic-errors'' compilation parameters makes a difference
for CLANG (x86-65 clang (trunk)) compiler - it starts reporting an error
instead of warning.

Meanwhile GCC (x86-64 gcc (trunk)) works fine (without a warning) for both
      "Foo**" -> "Foo** const" conversion and
for  "Foo**" -> "Foo* const * const" conversion.
But it shows an error with "Foo**"  -> "Foo const * const * const".

The conversion "Foo**" -> "Foo const * const * const" is not explicitly
prohibited by C standard and yes, it has been known for a long time. Has
been known as a "safe conversion" :)
"Safe conversion" which has quite useful use-cases.
And I think array of pointers and const-INVARIANTS are two quite widely
used "patterns".

It might be a subject to warning, but it is not an error. Because it
implies no erroneous behaviour, clear and well understandable.
I think tomorrow GCC might silently start reporting such conversion as just
a warning, or even without a warning at all.
And I think nobody will be arguing against it.
So, let's make these useful changes to GCC (I personally consider this as a
bug) earlier.

Respectfully,
Aleksandr G Povaliaev.

пт, 28 нояб. 2025 г. в 23:14, Andrey Tarasevich <[email protected]>:

> I'm not sure how you managed to obtain that "makes only difference to
> CLANG" result in your experiments. A simple code sample
>
>   void foo(const int *const *p) {}
>   int main(void) {
>     int **p = 0;
>     foo(p);
>   }
>
> immediately demonstrates that GCC and Clang in '-pedantic-errors'
> mode both issue an "error" message for this code (and abort
> compilation).
> Both compilers behave identically in this regard. This
> applies to
> your original code as well.
>
> Now, the portions of C language standard that make it a hard error are:
>
> * List of constraints for "Simple assignment"
>
>   https://port70.net/~nsz/c/c11/n1570.html#6.5.16.1p1
>
>   (which also apply to initialization), and
>
> * "Type qualifiers" section, which explains how qualifiers affect type
>   compatibility
>
>   https://port70.net/~nsz/c/c11/n1570.html#6.7.3p10
>
> (The above links refer to an older version of the document, but it is
> good enough for our purposes).
>
> The former states that you can only assign to each other pointers to
> "qualified or unqualified versions of _compatible_ types". The latter says
> that in order for two types to be compatible wrt qualifiers, both types
> have to be _identically_ qualified.
>
> That "qualified or unqualified versions" part is what permits you to
> convert
> 'T *' to 'const T *', i.e. there's some freedom wrt qualifiers at the very
> first level of indirection. But there's no such freedom at deeper levels
> of indirection: all qualifiers at the deeper levels have to be absolutely
> positively 100% identical. Otherwise, the constraint is violated,
> which is a hard error.
>
> I'm not sure what specific "C FAQ" you are referring to here, but it is
> besides the point anyway. FAQs are not normative. Language standard is.
>
> Finally, there's no room for "little bit early" of any kind here. The
> issue in question is well-known and already researched to death. It is
> anscient, meaning that "early" is not really an appropriare word here.
>
> And it is really not a debate. When I posted my original answer, the
> matter has been closed. All we are doing at this point
> is trying to
> help you understand this issue, which has obviously proven to be a bit
> surprising
> to you.
>
> --
> Best regards,
> Andrey
>
> P.S. Yes, the 'void *' trick does work as a workaround here. Albeit it is
> a fairly inelegant one...
>

Reply via email to