the "const" qualifier

Doug Gwyn gwyn at smoke.BRL.MIL
Mon Oct 16 14:45:55 AEST 1989


In article <12239 at cit-vax.Caltech.Edu> andy at csvax.caltech.edu (Andy Fyfe) writes:
>The GNU C compiler permits assignment (where assignment includes
>things such as parameter passing) of a "char *" to a "const char *",
>but not of a "char **" to a "const char **" without an explicit
>cast.  Rms assures me that this is in strict accordance with the
>ANSI standard.

Yes, the arguments must be "assignment compatible" with the corresponding
parameters declared in the prototype.  The rules for this are given in
Section 3.3.16.1 "Constraints".  Violation of a Constraint requires that
a diagnostic be issued.  The relevant constraint from 3.3.2.2 is that the
(zeroth-level) argument type must be assignable to the (zeroth-level)
parameter type after the parameter type has the 0th-level type qualifiers
stripped (the qualifier is second-level in this example), and the relevant
assignment-compatibility constraints are that the (first-level) types
pointed to, i.e. (const char *) and (char *), be compatible ignoring
FIRST-LEVEL qualifiers (there are none in this example), and the type
pointed to by the parameter type, i.e. (const char *), have all the
qualifiers of the type pointed to by the argument type, i.e. (char *),
which it does NOT -- thus the constraint violation.  Note that the
first-level ignoring of qualifiers on the pointed-to types allows a
(char *) argument to be passed without casting to a function declared as
taking a (const char *) parameter, but the qualifier-ignoring does not
occur at second or lower levels.

>	extern int execv(const char *path, const char **args);
>... my understanding of such a prototype is that the
>function will not change the characters pointed to by "path", or
>by "args[0], args[1], ...".  Passing pointers that permit such
>changes I would expect to be allowed (and is, for "path").

You understand the meaning okay.  The problem ultimately stems from a
slight overloading of semantics for "const".  You have to either use
compatible types, or use a cast when invoking the function.

Another interesting possibility is to declare the second argument as
(char * const *), which is true of execv() (it doesn't modify the
pointers in the args[] array either).  While not as helpful as what
you want, it works with the special rule for pointer first levels as
explained previously.  Of course the fully constrained spec is
	extern int execv( const char *path, const char *const *args );

Personally I would opt for
	extern int execv( const char *path, char *const *args );
as the most restrictive declaration that doesn't cause user hassles.



More information about the Comp.std.c mailing list