C 分配<;指向常量数组的指针>;=&书信电报;指向数组的指针>;:不兼容指针

C 分配<;指向常量数组的指针>;=&书信电报;指向数组的指针>;:不兼容指针,c,pointers,constants,compiler-warnings,gcc-warning,C,Pointers,Constants,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 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:

2)MSVC(AS C++代码)版本“VS2012CTP”,17.51025为x86:

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

编辑:


我只是在我的VisualStudio上把它编译成C代码(不是C++),它没有任何错误,也没有任何警告。我在上面的代码中编辑了注释

这是C和C++的区别。这种类型的const转换在C++中是完全好的,但是在C.< /P> < P> <代码> GCC < /C> >这里是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):

对于要兼容的两种指针类型,两种指针都应具有相同的合格性,并且都应 成为指向兼容类型的指针

pda
cpda
的类型具有相同的限定条件[完全不限定],因此问题是它们是否指向兼容类型,即
double[3]
const double[3]
兼容类型

6.7.6.2(6):

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

所以问题是
double
constdouble
是否是兼容类型

6.7.3(10):

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

我想说这使得
double
constdouble
不兼容,所以gcc是正确的

初始化

double const * cpd = pd;
可以,因为6.5.16.1列表中的分配约束(与初始化相关)

左操作数具有原子、限定或非限定指针类型,以及 左值转换后左操作数的类型)两个操作数都是 指向兼容类型的合格或不合格版本的指针,以及指向的类型 左边的to具有右边所指类型的所有限定符

作为可接受的情况之一
cpd
pd
都指向限定版本的
double
,左操作数的目标具有右操作数的所有限定符(还有一个,
const

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

double const * * cppd = ppd;

再次无效,需要诊断消息。< / P>是的,微软C++确实是比较糟糕的。我试图在VS2010中编译为C代码(参见编辑)。但这也是一个糟糕的比较,因为微软不支持C99,而不仅仅是C和C++的区别。编译C代码时发出的叮当声与这里的MSVC类似。这里有输入错误:“其中T1是指向常数T的数组N的指针,T2是指向常数T的数组N的指针。”-必须完全相反。它不能解释这一点

double const*cpd=pd;//gcc:ok
。根据您的研究,
double const*
double*
是不兼容的,因为它们指向不兼容的类型。但是gcc却不这么认为。不,虽然指针类型不兼容,但6.5.16.1明确允许将
double*
赋值给
const double*
,请参见添加。@n.m。谢谢,我现在明白了为什么这样做很危险