赋值 = :不兼容的指针

当我编译这样的东西

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

gcc警告我

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

问题:这项任务有什么问题? 是的,从技术上讲,这些是不同的类型,但我没有看到任何危险, double const (*)[ 3 ]看起来比double (*)[ 3 ]更安全。

我做了一些测试,结果让我更加困惑:

1)MSVC非常满意double const (* cpda)[ 3 ] = pda; 分配,没有错误,没有警告。

2)gcc和MSVC都很满意

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

虽然这些也是不同的类型。

3)在这个例子中

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

gcc给出相同的警告,但MSVC给出错误(!)。

谁在这? gcc还是MSVC?


检测结果。

编译:

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

2)用于x86的MSVC(作为C ++代码)版本’VS2012CTP’17.00.51025: http ://rise4fun.com/vcpp

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; } 

编辑:

我刚刚在我的Visual Studio上将其编译为C代码(而不是C ++)并且它没有提供任何错误,也没有任何警告。 我编辑了以上代码的评论

gcc就在这里,C中需要诊断。

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

基本上,您正在尝试将类型为T1的对象分配给类型为T2的对象(简单赋值的约束适用于初始化)。

其中T1是指向T的数组N的指针。

T2是指向const T的数组N的指针。

在简单赋值的约束中,C表示对于指针,以下内容应该成立(在C99中,6.5.16.1p1):

两个操作数都是指向兼容类型的限定或非限定版本的指针,左边指向的类型具有右边指向的所有类型的限定符。

这将允许例如:

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

但在您的示例中,指向const T的数组N的指针不是指向T的数组N的指针的限定版本。 在C中,数组不能是常量:没有const数组,只有const数组的数组。

这是对标准解释的不同,gcc认为类型不兼容,而MSVC和clang则不同。

6.7.6.1(2):

要使两个指针类型兼容,两者都应具有相同的限定条件,并且两者都应是兼容类型的指针。

pdacpda的类型是相同的[完全不合格],所以问题是它们是否指向兼容类型,即double[3]const double[3]兼容类型?

6.7.6.2(6):

要使两个数组类型兼容,两者都应具有兼容的元素类型,如果两个大小说明符都存在,并且是整数常量表达式,则两个大小说明符应具有相同的常量值。 如果在要求它们兼容的上下文中使用这两种数组类型,则如果两个大小说明符计算为不相等的值,则它是未定义的行为。

所以问题是doubleconst double是否是兼容类型。

6.7.3(10):

要使两种合格类型兼容,两者都应具有相同类型的兼容类型; 说明符或限定符列表中类型限定符的顺序不会影响指定的类型。

我会说使doubleconst double不兼容,所以gcc是对的。

初始化

 double const * cpd = pd; 

没关系,因为6.5.16.1列表中的赋值约束(与初始化相关)

左操作数具有primefaces,限定或非限定指针类型,并且(考虑左值操作数在左值转换后将具有的类型)两个操作数都是指向兼容类型的限定或非限定版本的指针,左侧指向的类型具有全部右边指出的类型的限定词;

作为可接受的情况之一。 cpdpd都指向double限定版本,左操作数的目标具有右边的所有限定符(以及另一个const )。

但是, double*const double*类型不兼容

 double const * * cppd = ppd; 

再次无效,需要诊断消息。

这是C和C ++之间的区别。 在C ++中进行这种类型的const转换是完全正常的,但在C语言中则不行。