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
It's a difference in interpretation of the standard, gcc considers the types not compatible, while MSVC and clang do.
6.7.6.1 (2):
The types of
pda
andcpda
are identically qualified [not qualified at all], so the question is whether they point to compatible types, i.e. aredouble[3]
andconst double[3]
compatible types?6.7.6.2 (6):
So the question is whether
double
andconst double
are compatible types.6.7.3 (10):
I would say that makes
double
andconst double
not compatible, so gcc is right.The initialisation
is okay because the constraints of assignment (which are relevant for initialisation) in 6.5.16.1 list
as one of the admissible situations.
cpd
andpd
both point to qualified versions ofdouble
, and the left operand's target has all qualifiers that the right has (and one more,const
).However, the types
double*
andconst double*
are not compatible, henceis again invalid, and requires a diagnostic message.
gcc
is right here and the diagnostic is required in C.Basically you are trying to assign an object of type
T1
to an object of typeT2
(constraints of simple assignment apply for initializations).Where
T1
is a pointer to an arrayN
ofT
.And
T2
is a pointer to an arrayN
ofconst T
.In the constraints of the simple assignment, C says that for pointers the following shall hold (in C99, 6.5.16.1p1):
This would allow for example something like:
But in your example, a pointer to an array
N
ofconst T
is not a qualified version of a pointer to an arrayN
ofT
. In C an array cannot be constant: there is notconst
arrays, but only arrays ofconst
elements.This is a difference between C and C++. Doing that type of const conversion is perfectly fine in C++, but not in C.