Search code examples
cpointersconstantscompiler-warningsgcc-warning

Assignment <pointer to array of constants> = <pointer to array>: incompatible pointers


When I compile something like this

double da[ 3 ] = { 2., 3., 4. };
double (* pda)[ 3 ] = &da;
double const (* cpda)[ 3 ] = pda; // gcc: warning; MSVC: ok

gcc warns me

warning: initialization from incompatible pointer type [enabled by default]

Question: What's the problem with this assignment? Yes, technically, these are different types, but I don't see any danger here, double const (*)[ 3 ] looks even safer for me than double (*)[ 3 ].

I did some tests and results confuse me even more:

1) MSVC is quite happy with double const (* cpda)[ 3 ] = pda; assignment, no errors, no warnings.

2) Both gcc and MSVC are happy with this

double d = 1.;
double * pd = &d;
double const * cpd = pd;  // gcc: ok; MSVC: ok

while these are different types too.

3) In this example

double d = 1.;
double * pd = &d;
double * * ppd = &pd;
double const * * cppd = ppd;  // gcc: warning; MSVC: error

gcc gives the same warning but MSVC gives error(!).

Who is right here? gcc or MSVC?


Test results.

Compilers:

1) gcc version 4.7.2: http://www.compileonline.com/compile_c_online.php

2) MSVC (as C++ code) version 'VS2012CTP' 17.00.51025 for x86: http://rise4fun.com/vcpp

3) MSVC (as C code) VS2010: tested offline

int main()
{
    double d = 1.;

    double * pd = &d;
    double const * cpd = pd;
    // gcc: ok
    // MSVC C++: ok
    // MSVC C: ok

    double * * ppd = &pd;
    double const * * cppd = ppd;
    // gcc: warning: initialization from incompatible pointer type [enabled by default]
    // MSVC C++: error C2440: 'initializing' : cannot convert from 'double **' to 'const double **'
    // MSVC C: ok

    double da[ 3 ] = { 2., 3., 4. };

    double (* pda)[ 3 ] = &da;
    double const (* cpda)[ 3 ] = pda;
    // gcc: warning: initialization from incompatible pointer type [enabled by default]
    // MSVC C++: ok
    // MSVC C: ok

    cpd, cpda;
    return 0;
}

Edit:

I just compiled this on my Visual Studio as C code (not C++) and it gives no errors, no warnings at all. I edited commentaries to above code


Solution

  • gcc is right here and the diagnostic is required in C.

    double da[ 3 ] = { 2., 3., 4. };
    double (* pda)[ 3 ] = &da;
    double const (* cpda)[ 3 ] = pda;  // diagnostic here
    

    Basically you are trying to assign an object of type T1 to an object of type T2 (constraints of simple assignment apply for initializations).

    Where T1 is a pointer to an array N of T.

    And T2 is a pointer to an array N of const T.

    In the constraints of the simple assignment, C says that for pointers the following shall hold (in C99, 6.5.16.1p1):

    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

    This would allow for example something like:

    int a = 0;
    const int *p = &a;  // p type is a qualified version of &a type
    

    But in your example, a pointer to an array N of const T is not a qualified version of a pointer to an array N of T. In C an array cannot be constant: there is not const arrays, but only arrays of const elements.