4

The following code compiles without warning on GCC but gives a warning in Visual Studio 2005.

const void * x = 0;
char * const * p = x;

x points to a constant object of unknown type, and p points to a constant pointer to char. Why should the assignment to p result in a warning?

Again, this is C, not C++. Thanks.

sharkin
  • 12,162
  • 24
  • 86
  • 122
Fred
  • 41
  • 1
  • 2
  • could you add the warning message? – Etan Oct 26 '09 at 11:52
  • 2
    Agree with Etan: this question would have been much clearer if the warning message was stated. It is: warning C4090: 'initializing' : different 'const' qualifiers – user200783 Oct 26 '09 at 12:01
  • My VS2005 (configured to C++) actually returns an error in this case: 'initializing' : cannot convert from 'const void *' to 'char *const *'. Conversion from 'void*' to pointer to non-'void' requires an explicit cast – Igor Oct 26 '09 at 12:04
  • 2
    Compiling the code as C should give you the C4090 warning. – user200783 Oct 26 '09 at 12:07
  • 1
    Some compilers issue warnings even with `void *` conversions when they see that the pointers appear to have different level of indirection. This might be the reason fro MSVC++ warning. Otherwise, there's no problems with this code. – AnT stands with Russia Oct 26 '09 at 14:05
  • Do you get a warning without the `const`s? – pmg Oct 26 '09 at 21:37

6 Answers6

5

It happens because when you make a pointer of one type point to another type, sometimes it is done unintentionally (bug), so the compiler warns you about it.

So, in order to tell the compiler that you actually intent to do it, you have to do explicit casting, like this:

        const void * x = 0;
        char * const * p = (char * const * )x;

P.S. At the first place I wrote "most of the times is done unintentionally", but AndreyT made me reconsider it when he rightfully said that void * exists specifically for that purpose.

Igor
  • 26,650
  • 27
  • 89
  • 114
  • this is a c++-style "clobber the type" approach. the correct solution is different in C. – Matt Joiner Oct 26 '09 at 13:21
  • 1
    `void *` exists specifically for that purpose. Issuing warnings on that would be completely useless. The only justification for a warning in this case might be the apparent different level of indirection in pointers, not just because they point to different types. – AnT stands with Russia Oct 26 '09 at 15:19
3

The C code is valid and a conforming compiler shouldn't warn as const ness is correctly preserved and conversion of void * to any pointer type (function pointers aside) is implicit.

A C++ compiler is supposed to warn about the implicit conversion, but a warning about discarding the const qualifier is wrong and should be considered a compiler bug.

Christoph
  • 164,997
  • 36
  • 182
  • 240
0

What if x would point to, say, a struct Thing as opposed to a char? In that case, you'd be doing something with unspecified behavior. GCC tends to let you do this because it assumes that you're smart enough not to shoot yourself in the foot, but there is good reason for the warning.

pavpanchekha
  • 2,073
  • 1
  • 17
  • 23
  • 1
    gcc let's you do this because the standard says `void *` can be converted to any pointer type (function-pointers aside) implicitly – Christoph Oct 26 '09 at 12:17
0

You have to read the following from right to left.
char * const * p = x;

For Example:
P points to a const pointer of type char.

Chad
  • 2,938
  • 3
  • 27
  • 38
0
const void * x = 0;
char * const * p = x;

At first I assumed you meant to take the address of x and wrote the code for that. Then I decided that x points to a pointer to char []. Both anyway, and it's still quite confusing:

#include <stdio.h>
int main()
{
        char s [] = "Hello World!";
        const void * x = s;
        const char * const * const p = (const char * const *)&x;
        printf("%s\n", *p);
/* won't compile
        *p++;      // increments x to point to 'e'
        (**p)++;   // increments 'H' to 'I'
*/
        const char * y = s;
        x = &y;
        const char * const * const q = x;
        printf("%s\n", *q);
/* won't compile
        *q++;
        (**q)++;
*/
        return 0;
}

The extra const before the char in the declaration of p prevents (**p)++ from compiling. However, the added const before the declaration of q (in GCC) shadows warning: dereferencing ‘void *’ pointer with error: increment of read-only location ‘**q’ for (**q)++. Hope that helps, it has helped me a little :-)

James Morris
  • 4,867
  • 3
  • 32
  • 51
-2
warning C4090: 'initializing' : different 'const' qualifiers

You cannot cast const void to char *const or even char *. By dereferencing p, you can now modify *(char *)(*x). This is a little known subtlety about pointers in C.

A working type for p would be:

char const **p = x;

And yes, I put const on the right like a man.

Matt Joiner
  • 112,946
  • 110
  • 377
  • 526
  • the warning is wrong as `const` ness is preserved (remember to read declarations inside-out and that `const void` is the same as `void const`) – Christoph Oct 26 '09 at 12:18
  • nope. ran this on a C compiler. the problem is stuffing the const void into char *const. by dereffing p you can now modify x. – Matt Joiner Oct 26 '09 at 13:14
  • 2
    That doesn't make any sense. There's no way to modify `x` through `p`. We never take the address of `x` anywhere in the code. – AnT stands with Russia Oct 26 '09 at 14:01