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):
For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.
The types of pda
and cpda
are identically qualified [not qualified at all], so the question is whether they point to compatible types, i.e. are double[3]
and const double[3]
compatible types?
6.7.6.2 (6):
For two array types to be compatible, both shall have compatible element types, and if both size specifiers are present, and are integer constant expressions, then both size specifiers shall have the same constant value. If the two array types are used in a context which requires them to be compatible, it is undefined behavior if the two size specifiers evaluate to unequal values.
So the question is whether double
and const double
are compatible types.
6.7.3 (10):
For two qualified types to be compatible, both shall have the identically qualified version of a compatible type; the order of type qualifiers within a list of specifiers or qualifiers does not affect the specified type.
I would say that makes double
and const double
not compatible, so gcc is right.
The initialisation
double const * cpd = pd;
is okay because the constraints of assignment (which are relevant for initialisation) in 6.5.16.1 list
the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) 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;
as one of the admissible situations. cpd
and pd
both point to qualified versions of double
, and the left operand's target has all qualifiers that the right has (and one more, const
).
However, the types double*
and const double*
are not compatible, hence
double const * * cppd = ppd;
is again invalid, and requires a diagnostic message.
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.
This is a difference between C and C++. Doing that type of const conversion is perfectly fine in C++, but not in C.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With