Hi Bruno,

On Thu, Jan 15, 2026 at 11:04:37AM +0100, Bruno Haible wrote:
> Alejandro Colomar wrote:
> > I've had the idea today of an implementation that would be even better
> > for users, not requiring the cast at all.
> > 
> >     $ cat execve4.c 
> >     #include <stddef.h>
> > 
> >     #ifdef __cplusplus
> >     # define const_cast(T, p)  p
> >     #else
> >     # define const_cast(T, p)  _Generic(p, const T: (T) (p), default: (p))
> >     #endif
> > 
> >     #ifdef __cplusplus  // Have n3749
> >     int execve(const char *path, const char *const a[], const char *const 
> > e[]);
> >     #else
> >     # define execve(p, a, e)  execve(p, const_cast(char*const*,a), 
> > const_cast(char*const*,e))
> >     int (execve)(const char *path, char *const a[], char *const e[]);
> >     #endif
> 
> Very nice!

Thanks!  :-)

> This can even be done in Gnulib, without waiting for libc changes.

I have something even better for Gnulib.  See below.

> And for older compilers (that don't support _Generic), we can use an explicit
> cast:
> 
>       #ifdef __cplusplus
>       # define const_cast(T, p)  p
>       #elif (defined __GNUC__ && __GNUC__ + (__GNUC_MINOR__ >= 9) > 4) \
>             || (defined __clang__ && __clang_major__ >= 3) \
>             || (defined __SUNPRO_C && __SUNPRO_C >= 0x5150) \
>             || (__STDC_VERSION__ >= 201112L && !defined __GNUC__)
>       # define const_cast(T, p)  _Generic(p, const T: (T) (p), default: (p))
>       #else
>       # define const_cast(T, p)  (T) (p)
>       #endif
> 
> > The only place programmers would notice the different prototype would be
> > in function pointers, but that's where Chris's proposal N3674 would kick
> > in.  It would allow unidirectional implicit conversions of functions
> > where one is more restrictive than the other regarding qualifiers.
> 
> I see. Yes, then N3674 makes a lot of sense: The language would feel
> incomplete if this implicit conversion from 'char **' to 'const char **'
> was allowed in argument passing but not in function pointer types.

Yup.

BTW, I wrote an implementation where you still get the old prototype
when using function pointers, for compilers without N3674.  This one,
you could already merge in Gnulib, I think.

        #include <stddef.h>
        #include <unistd.h>

        #ifdef __cplusplus
        # define CONST_CAST(T, p)  const_cast<T>(p)
        #else
        # define CONST_CAST(T, p)  _Generic(p, const T: (T) (p), default: (p))
        #endif

        #define execve_casted(p, a, e)  execve(p, CONST_CAST(char*const*,a), 
CONST_CAST(char*const*,e))

        static inline int
        execve_const(const char *path, const char *const a[], const char *const 
e[])
        {
                return execve_casted(path, a, e);
        }

        #ifdef __cplusplus  // Have n3749
        # define execve(...)  execve_const(__VA_ARGS__)
        #else
        # define execve(...)  execve_casted(__VA_ARGS__)
        #endif

        typedef int Told(const char *,       char *const[],       char 
*const[]);
        typedef int Tnew(const char *, const char *const[], const char 
*const[]);

        int
        main(void)
        {
                      char *       argv [] = {"foo", "bar", NULL};  // 
-Wdiscarded-qualifiers
                const char *      cargv [] = {"foo", "bar", NULL};
                      char *const  argvc[] = {"foo", "bar", NULL};  // 
-Wdiscarded-qualifiers
                const char *const cargvc[] = {"foo", "bar", NULL};

                Told  *fpold;
                Tnew  *fpnew;

                execve("foo",  argv , NULL);
                execve("foo", cargv , NULL);  // error: 
-Wincompatible-pointer-types; fixed by n3749
                execve("foo",  argvc, NULL);
                execve("foo", cargvc, NULL);

                fpold = execve;
                fpold = execve_const;  // error: -Wincompatible-pointer-types; 
should be fixed by n3674
                //fpnew = execve;      // error: -Wincompatible-pointer-types;
                fpnew = execve_const;
        }

If you take this, please add:

        Co-authored-by: Alejandro Colomar <[email protected]>


Have a lovely night!
Alex

-- 
<https://www.alejandro-colomar.es>

Attachment: signature.asc
Description: PGP signature

Reply via email to