const char ** incompatible with char ** (and vice versa)? 
Author Message
 const char ** incompatible with char ** (and vice versa)?

Greetings all.  This question may sound like a
nit-picker but it's popped up a few times in the
"real world" and nobody I've come across has been
able to answer it with any sort of decent
reasoning.

Using gcc 2.95.2 under GNU/Linux and compiling the
following snippit of code:

int
main(void)
{
  const char **p2p_const;
  char **p2p;
  p2p_const=p2p;
  return 0;

Quote:
}

(char could be replaced with any other type)

The compiler emits the warning:

foo.c: In function `main':
foo.c:6: warning: assignment from incompatible
pointer type

This is annoying more than anything, especially
went code is compiled such that warnings are
treated like errors.

Using a const char ** cast gets rid of the warning
but what I (sadly) fail to realize is why, in the
first place, the two pointer types are
incompatible.

Anybody with an enlightening explanation?  Please
share. :)

Regards,
kw

Sent via Deja.com
http://www.*-*-*.com/



Tue, 17 Jun 2003 05:51:05 GMT  
 const char ** incompatible with char ** (and vice versa)?

Quote:

> int
> main(void)
> {
>   const char **p2p_const;
>   char **p2p;
>   p2p_const=p2p;
>   return 0;
> }
> foo.c: In function `main':
> foo.c:6: warning: assignment from incompatible
> pointer type

Ah, yes, this ugly, annoying problem catches me out from time to
time too.  The FAQ has the answer:

11.10:  Why can't I pass a char ** to a function which expects a
        const char **?

A:      You can use a pointer-to-T (for any type T) where a pointer-to-
        const-T is expected.  However, the rule (an explicit exception)
        which permits slight mismatches in qualified pointer types is
        not applied recursively, but only at the top level.

        You must use explicit casts (e.g. (const char **) in this case)
        when assigning (or passing) pointers which have qualifier
        mismatches at other than the first level of indirection.

        References: ISO Sec. 6.1.2.6, Sec. 6.3.16.1, Sec. 6.5.3; H&S
        Sec. 7.9.1 pp. 221-2.

--
"I should killfile you where you stand, worthless human." --Kaz



Tue, 17 Jun 2003 06:12:06 GMT  
 const char ** incompatible with char ** (and vice versa)?

Quote:

>int
>main(void)
>{
>  const char **p2p_const;
>  char **p2p;
>  p2p_const=p2p;
>  return 0;
>}

>(char could be replaced with any other type)

>The compiler emits the warning:

>foo.c: In function `main':
>foo.c:6: warning: assignment from incompatible
>pointer type

This diagnostic is required by ANSI C, because a pointer to a const
const char and a pointer to char are not compatible types.

The C conversion rules allow an assignment from unqualified T *
to const T *, even though the two types are incompatible. Similar
freedom applies to initialization of objects such as function parameters, and
returning values from functions.  However, this special allowance does not
extend to pointers derived from these two types: you cannot assign an
unqualified T ** to an lvalue of type const T **.

In principle, such a conversion should be safe, so in some ways this is a
pathological consequence of the language rules, which deem differently
qualified types to be incompatible, even though they share the same
representation. The rules do prohibit certain programs from being considered
correct, for example a program which in one translation unit contains the
external definition ``const int x = 3;'' and in another unit the declaration
``extern int x''. The behavior of this program is undefined if the reference is
used, because its type is incompatible with that of the definition.

Quote:
>This is annoying more than anything, especially
>went code is compiled such that warnings are
>treated like errors.

>Using a const char ** cast gets rid of the warning
>but what I (sadly) fail to realize is why, in the
>first place, the two pointer types are
>incompatible.

Because if they were allowed to be compatible, it could open up certain holes
in the language, like a

    struct foo {
        const int x, y;
    };

in one translation unit being compatible with

    struct bar {
        int x, y;
    };

which is open to abuses. Of course, a C program which does this type of
thing anyway is nevertheless widely portable due to the lack of run time
diagnosis for this type of thing.

I'm finding it difficult to enumerate the implications that such a change would
have; if we have a longer comp.lang.c debate about this I'm sure a lot of good
reasons will come to light for differently qualified types being incompatible.  



Tue, 17 Jun 2003 06:25:17 GMT  
 const char ** incompatible with char ** (and vice versa)?

[discussing incompatibility of const T ** and T ** for type T]

Quote:
> Because if they were allowed to be compatible, it could open up certain holes
> in the language, like a

>     struct foo {
>    const int x, y;
>     };

> in one translation unit being compatible with

>     struct bar {
>    int x, y;
>     };

> which is open to abuses. Of course, a C program which does this type of
> thing anyway is nevertheless widely portable due to the lack of run time
> diagnosis for this type of thing.

I don't think that making const T ** and T ** compatible is a
great idea either.  I think that making the latter acceptable for
assignment to the former is a better idea.  Such a change could
be made just by modifying the constraint in C99 section 6.15.16.1
"Simple assignment" from

        -- both operands are pointers to qualified or unqualified
           versions of compatible types, and the type pointed to
           by the left has all the qualifiers of the type pointed
           to by the right;

to a more general test, and similarly for the next constraint in
the list.

This change wouldn't open up the hole that you pointed out above
AFAICS.

Quote:
> I'm finding it difficult to enumerate the implications that
> such a change would have; if we have a longer comp.lang.c
> debate about this I'm sure a lot of good reasons will come to
> light for differently qualified types being incompatible.

Agreed.

(BTW, Kaz, your lines are getting a bit long even after just one
quoting, so I've reflowed the paragraph above.)
--
"This is a wonderful answer.
 It's off-topic, it's incorrect, and it doesn't answer the question."
--Richard Heathfield



Tue, 17 Jun 2003 06:41:00 GMT  
 const char ** incompatible with char ** (and vice versa)?

Quote:
> Ah, yes, this ugly, annoying problem catches me out from time to
> time too.  The FAQ has the answer:


but only looked at the "pointers", "arrays and pointers", and "strange
problems" sections; I didn't think to look in the "standard C" section.

:/

Thanks again!

kw

Sent via Deja.com
http://www.deja.com/



Tue, 17 Jun 2003 06:49:52 GMT  
 const char ** incompatible with char ** (and vice versa)?

Quote:

> >Using a const char ** cast gets rid of the warning
> >but what I (sadly) fail to realize is why, in the
> >first place, the two pointer types are
> >incompatible.

> Because if they were allowed to be compatible, it could open up
certain holes
> in the language, like a

>     struct foo {
>    const int x, y;
>     };

> in one translation unit being compatible with

>     struct bar {
>    int x, y;
>     };

While I agree with the general thrust of what you are saying, I think
const-ness or the lack thereof is he only tip of the iceberg here.
Assigning from a pointer-to-struct-foo to a pointer-to-struct-bar will
get a (well-deserved) warning even their members were declared
identically.

The thing that freaks me out is that the following code compiles with
only that same warning about incompatible pointers. Since we are used
to seeing this warning so much of the time, we might even ignore the
warning. Until we actually try to RUN the program, that is.

    #include <stdio.h>

    struct foo {
        int x,y;
    };

    struct bar {
        int x, y, z;
    };

    int main(void)
    {
        struct bar *barptr;
        struct foo a = { 1, 2};
        barptr = &a;

        barptr->z = 3; // watch out!
        printf("%d,%d,%d\n", barptr->x, barptr->y, barptr->z);

        return 0;
    }

Sent via Deja.com
http://www.deja.com/



Tue, 17 Jun 2003 10:31:22 GMT  
 const char ** incompatible with char ** (and vice versa)?

Quote:
>(BTW, Kaz, your lines are getting a bit long even after just one
>quoting, so I've reflowed the paragraph above.)

Hmm, maybe I should format narrower in anticipation of heavy quoting.
;) I stick to the 79 rule quite literally, which doesn't leave any
padding. Time to add a :set wrapmargin=8 to my vimrc. :)


Tue, 17 Jun 2003 14:55:07 GMT  
 const char ** incompatible with char ** (and vice versa)?

Quote:


>>(BTW, Kaz, your lines are getting a bit long even after just one
>>quoting, so I've reflowed the paragraph above.)
> Hmm, maybe I should format narrower in anticipation of heavy quoting.
> ;) I stick to the 79 rule quite literally, which doesn't leave any
> padding. Time to add a :set wrapmargin=8 to my vimrc. :)

If you're using vim, be warned that textwidth (tw) is preferable,
as wrapmargin is relative to the current window size, while tw is
absolute.  :set tw=72 will keep your message the same width even
if you resize your terminal.

--



Wed, 18 Jun 2003 15:11:02 GMT  
 const char ** incompatible with char ** (and vice versa)?

Quote:

> The thing that freaks me out is that the following code compiles with
> only that same warning about incompatible pointers. Since we are used
> to seeing this warning so much of the time, we might even ignore the
> warning. Until we actually try to RUN the program, that is.

You'd ignore an "assignment from incompatible pointer type" warning?
I use gcc -Werror to build my projects, so I don't have that option
:-)

--



Wed, 18 Jun 2003 17:00:34 GMT  
 const char ** incompatible with char ** (and vice versa)?
On Fri, 29 Dec 2000 02:31:22 GMT, Jeff Robertson

Quote:

>The thing that freaks me out is that the following code compiles with
>only that same warning about incompatible pointers.

That warning flags an ANSI C constraint rule violation.  The C standard
makes no distinction between a warning and error; it uses the term
``diagnostic''. There is no difference in emphasis among any of the
diagnosable errors: an assignment between incompatible pointers is
equal in stature to a missing semicolon after a declaration or
unbalanced parentheses in an expression. All of these require a
diagnostic, and do not require successful translation and execution.
Do not ignore warnings; some of them could be required ANSI C
diagnostics!

Quote:
>Since we are used
>to seeing this warning so much of the time, we might even ignore the
>warning.

Much of the time? Ouch!


Wed, 18 Jun 2003 18:33:25 GMT  
 const char ** incompatible with char ** (and vice versa)?

Quote:

> I use gcc -Werror to build my projects, so I don't have that option

Yeah, me too.  Otherwise I find that I miss warnings because I
fix an error in one or two files and re-`make' and the files that
just had warnings don't get recompiled, so I don't get to fix
those warnings.

(Another item to add to the style guide.)
--
"You call this a *C* question? What the hell are you smoking?" --Kaz



Wed, 18 Jun 2003 23:10:25 GMT  
 const char ** incompatible with char ** (and vice versa)?

Quote:


>> I use gcc -Werror to build my projects, so I don't have that option
> Yeah, me too.  Otherwise I find that I miss warnings because I
> fix an error in one or two files and re-`make' and the files that
> just had warnings don't get recompiled, so I don't get to fix
> those warnings.

i used to do this but point that once i turned up the warning level some, it
became completely unreasonable.  for example, i have used to have
-Wpointer-arith turned on; the problem is that some of the glibc 2.1 header
files (dealing with strings i believe) used pointer arithmetic on void
pointers.  also, i've found that gcc gives spurious warnings wrt
setjmp()/vfork() clobberings.

--
 /"\                                                 m i k e   b u r r e l l

  X        AGAINST HTML MAIL,



Wed, 18 Jun 2003 23:26:38 GMT  
 const char ** incompatible with char ** (and vice versa)?

Quote:



> >> I use gcc -Werror to build my projects, so I don't have that option

> > Yeah, me too.  Otherwise I find that I miss warnings because I
> > fix an error in one or two files and re-`make' and the files that
> > just had warnings don't get recompiled, so I don't get to fix
> > those warnings.

> i used to do this but point that once i turned up the warning level some, it
> became completely unreasonable.  for example, i have used to have
> -Wpointer-arith turned on; the problem is that some of the glibc 2.1 header
> files (dealing with strings i believe) used pointer arithmetic on void
> pointers.  also, i've found that gcc gives spurious warnings wrt
> setjmp()/vfork() clobberings.

If I had problems like that I'd probably just turn it off for the
affected files and submit a patch against glibc2.1.
--
Just another C hacker.


Wed, 18 Jun 2003 23:33:21 GMT  
 const char ** incompatible with char ** (and vice versa)?

Quote:
> I don't think that making const T ** and T ** compatible is a
> great idea either.  I think that making the latter acceptable for
> assignment to the former is a better idea.  Such a change could
> be made just by modifying the constraint in C99 section 6.15.16.1
> "Simple assignment" from

>    -- both operands are pointers to qualified or unqualified
>            versions of compatible types, and the type pointed to
>            by the left has all the qualifiers of the type pointed
>            to by the right;

> to a more general test, and similarly for the next constraint in
> the list.

> This change wouldn't open up the hole that you pointed out above
> AFAICS.

I think that this *would* open up a whole because it would allow to
change a const object without diagnostic:

void unsafe(void)
{
   const int ci = 42;
   int  i = 0;
   int* pi = &i;
   int** ppi = &pi;
   int const ** ppci = ppi; /* ??? safe ??? */

   *ppci = &ci ; /* eqivalent to pi=&ic */
   *pi = 0;  /* equivalent to ci=0 , oops... */

Quote:
}

Regards
Horst


Thu, 19 Jun 2003 19:26:31 GMT  
 
 [ 14 post ] 

 Relevant Pages 

1. Assigning char* to int* and vice-versa???

2. Conversion : From OLECHAR* to char* and vice versa ?

3. Help: inline char const* const& max(char const* const &a, char const* const &b)

4. const char * vs char const *

5. const char *p == char const *p ?

6. char** and const char** ...

7. va_arg(ap, const char *) = char*?

8. const char* to char[64]

9. char^ to const char* casting

10. passing const char* to char* fails

11. const char* vs. char *

12. converting const char* to unsigned char[1024]

 

 
Powered by phpBB® Forum Software