赋值<pointer to =“”“array =”“of =”“constants =”“> = <pointer to =”“array =”“>:不兼容的指针</pointer> </pointer>

时间:2013-06-15 10:40:54

标签: c pointers const compiler-warnings gcc-warning

当我编译这样的东西时

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)MSVC(作为C ++代码)版本'VS2012CTP'17.00.51025 for x86: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 ++)并且它没有给出任何错误,也没有任何警告。我编辑了以上代码的评论

3 个答案:

答案 0 :(得分:7)

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

6.7.6.1(2):

  

要使两个指针类型兼容,两者都应具有相同的资格,并且两者都必须   是兼容类型的指针。

pdacpda的类型具有相同的资格[根本不合格],因此问题是它们是否指向兼容类型,即double[3]和{{1}兼容类型?

6.7.6.2(6):

  

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

所以问题是const double[3]double是否是兼容的类型。

6.7.3(10):

  

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

我会说const doubledouble不兼容,所以gcc是对的。

初始化

const double

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

  

左操作数具有原子,限定或非限定指针类型,并且(考虑到   两个操作数都是左值操作数在左值转换后的类型   指向兼容类型的限定或非限定版本的指针,以及指向的类型   左边的所有限定符都是右边所指示的类型;

作为可接受的情况之一。 double const * cpd = pd; cpd都指向pd的限定版本,左操作数的目标包含权限所有的限定符(还有一个,double)。

但是,constdouble*类型不兼容,因此

const double*

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

答案 1 :(得分:2)

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

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

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

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

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

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

  

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

这将允许例如:

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

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

答案 2 :(得分:1)

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