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
gcc警告我
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 ]
.
问题:这项任务有什么问题?是的,从技术上讲,这些是不同的类型,但我没有看到任何危险,双const(*)[3]看起来比双重(*)[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.
1)MSVC非常满意双const(* cpda)[3] = pda;分配,没有错误,没有警告。
2) Both gcc and MSVC are happy with this
2)gcc和MSVC都很满意
double d = 1.;
double * pd = &d;
double const * cpd = pd; // gcc: ok; MSVC: ok
while these are different types too.
虽然这些也是不同的类型。
3) In this example
3)在这个例子中
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(!).
gcc给出相同的警告,但MSVC给出错误(!)。
Who is right here? gcc or MSVC?
谁在这? gcc还是MSVC?
Test results.
Compilers:
1) gcc version 4.7.2: http://www.compileonline.com/compile_c_online.php
1)gcc版本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
2)用于x86的MSVC(作为C ++代码)版本'VS2012CTP'17.00.51025:http://rise4fun.com/vcpp
3) MSVC (as C code) VS2010: tested offline
3)MSVC(作为C代码)VS2010:离线测试
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
我刚刚在我的Visual Studio上将其编译为C代码(而不是C ++)并且它没有提供任何错误,也没有任何警告。我编辑了以上代码的评论
3 个解决方案
#1
2
gcc
is right here and the diagnostic is required in C.
gcc就在这里,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).
基本上,您正在尝试将类型为T1的对象分配给类型为T2的对象(简单赋值的约束适用于初始化)。
Where T1
is a pointer to an array N
of T
.
其中T1是指向T的数组N的指针。
And T2
is a pointer to an array N
of const T
.
T2是指向const T的数组N的指针。
In the constraints of the simple assignment, C says that for pointers the following shall hold (in C99, 6.5.16.1p1):
在简单赋值的约束中,C表示对于指针,以下内容应该成立(在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.
但是在你的例子中,指向const T的数组N的指针不是指向T的数组N的指针的限定版本。在C中,数组不能是常数:没有const数组,只有const数组的数组。
#2
6
It's a difference in interpretation of the standard, gcc considers the types not compatible, while MSVC and clang do.
这是对标准解释的不同,gcc认为类型不兼容,而MSVC和clang则不同。
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?
pda和cpda的类型是相同的[完全不合格],所以问题是它们是否指向兼容类型,即是double [3]和const double [3]兼容类型?
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.
所以问题是double和const double是否是兼容类型。
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.
我会说使double和const double不兼容,所以gcc是对的。
The initialisation
double const * cpd = pd;
is okay because the constraints of assignment (which are relevant for initialisation) in 6.5.16.1 list
没关系,因为6.5.16.1列表中的赋值约束(与初始化相关)
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
).
作为可接受的情况之一。 cpd和pd都指向double的限定版本,左操作数的目标具有右边的所有限定符(以及另一个const)。
However, the types double*
and const double*
are not compatible, hence
但是,double *和const double *类型不兼容
double const * * cppd = ppd;
is again invalid, and requires a diagnostic message.
再次无效,需要诊断消息。
#3
1
This is a difference between C and C++. Doing that type of const conversion is perfectly fine in C++, but not in C.
这是C和C ++之间的区别。在C ++中进行这种类型的const转换是完全正常的,但在C语言中则不行。
#1
2
gcc
is right here and the diagnostic is required in C.
gcc就在这里,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).
基本上,您正在尝试将类型为T1的对象分配给类型为T2的对象(简单赋值的约束适用于初始化)。
Where T1
is a pointer to an array N
of T
.
其中T1是指向T的数组N的指针。
And T2
is a pointer to an array N
of const T
.
T2是指向const T的数组N的指针。
In the constraints of the simple assignment, C says that for pointers the following shall hold (in C99, 6.5.16.1p1):
在简单赋值的约束中,C表示对于指针,以下内容应该成立(在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.
但是在你的例子中,指向const T的数组N的指针不是指向T的数组N的指针的限定版本。在C中,数组不能是常数:没有const数组,只有const数组的数组。
#2
6
It's a difference in interpretation of the standard, gcc considers the types not compatible, while MSVC and clang do.
这是对标准解释的不同,gcc认为类型不兼容,而MSVC和clang则不同。
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?
pda和cpda的类型是相同的[完全不合格],所以问题是它们是否指向兼容类型,即是double [3]和const double [3]兼容类型?
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.
所以问题是double和const double是否是兼容类型。
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.
我会说使double和const double不兼容,所以gcc是对的。
The initialisation
double const * cpd = pd;
is okay because the constraints of assignment (which are relevant for initialisation) in 6.5.16.1 list
没关系,因为6.5.16.1列表中的赋值约束(与初始化相关)
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
).
作为可接受的情况之一。 cpd和pd都指向double的限定版本,左操作数的目标具有右边的所有限定符(以及另一个const)。
However, the types double*
and const double*
are not compatible, hence
但是,double *和const double *类型不兼容
double const * * cppd = ppd;
is again invalid, and requires a diagnostic message.
再次无效,需要诊断消息。
#3
1
This is a difference between C and C++. Doing that type of const conversion is perfectly fine in C++, but not in C.
这是C和C ++之间的区别。在C ++中进行这种类型的const转换是完全正常的,但在C语言中则不行。