• Re: pedantic gcc and const 2D arrays

    From Andrey Tarasevich@[email protected] to comp.lang.c on Sun Apr 12 11:30:18 2026
    From Newsgroup: comp.lang.c

    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



    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Tim Rentsch@[email protected] to comp.lang.c on Mon Apr 13 05:40:50 2026
    From Newsgroup: comp.lang.c

    Andrey Tarasevich <[email protected]> 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).
    --- Synchronet 3.21f-Linux NewsLink 1.2