Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 29 May 2006 21:09:55 +1000 (EST)
From:      Bruce Evans <bde@zeta.org.au>
To:        Yar Tikhiy <yar@comp.chem.msu.su>
Cc:        freebsd-arch@freebsd.org
Subject:   Re: Can fts_open() be constified further?
Message-ID:  <20060529200215.T24032@delplex.bde.org>
In-Reply-To: <20060528164328.GA84031@comp.chem.msu.su>
References:  <20060528164328.GA84031@comp.chem.msu.su>

next in thread | previous in thread | raw e-mail | index | archive | help
On Sun, 28 May 2006, Yar Tikhiy wrote:

> Currently, fts_open() is declared as follows:
>
>     FTS *
>     fts_open(char * const *path_argv, int options,
>         int (*compar)(const FTSENT * const *, const FTSENT * const *));
>
> This means that one cannot pass pointers to constant strings in
> path_argv[] without getting rather justified warnings from cc.
> AFAIK, fts(3) functions aren't supposed to modify the path strings.
> Hence the prototype asks to be changed slightly:
>
>     fts_open(const char * const *path_argv, int options,
>              ^^^^^
> This shouldn't break fts consumers because a pointer to a variable
> can be converted to a pointer to a constant w/o warnings (but not
> the other way around.)  Can anybody see other possible side effects
> from such change?

It wouldn't work, for the same reasons that it doesn't work for execve():
plain "char **" cannot be converted to "const char * const *".

Only "const char **" and of course itself can be converted.
"char * const *" cannot be converted but is weird compared with "char **".

All this follows from the type rule that you expressed informally.
"const" can only be added at the outer level when the inner types are
the same. Set T1 = "char *" and T2 = "const char *" to reduce confusion
about the levels.  Then:

     char ** = pointer to T1                       = PT1
     char * const * = const pointer to T1          = CPT1
     const char ** = pointer to T2                 = PT2
     const char * const * = const pointer to T2    = CPT2

PT1 can be converted to CPT1 and PT2 can be converted to CPT2.  No other
conversions from adding a "const" are permitted, since T1 != T2.

The prototypes for the execve() family and presumably for fts_open() are
chosen so that the most important non-constified type (PT1) can be converted
to the type in the prototype (CPT1).

PT1 cannot be converted to CPT2 since "const" is not very well designed.
Allowing this conversion without redesigning "const" would make "const"
even less well designed.  From the draft C standard (n869.txt):

%%%
        [#6] EXAMPLE 3 Consider the fragment:

                const char **cpp;
                char *p;
                const char c = 'A';

                cpp = &p;       // constraint violation
                *cpp = &c;      // valid
                *p = 0;         // valid

        The first assignment is unsafe because it  would  allow  the
        following  valid  code to attempt to change the value of the
        const object c.
%%%

It looks harmless to add a "const" to the inner type in &p, but this example
shows that it unsafe.

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20060529200215.T24032>