当我编译这样的东西时
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 ++)并且它没有给出任何错误,也没有任何警告。我编辑了以上代码的评论
答案 0 :(得分:7)
这对标准的解释有所不同,gcc认为类型不兼容,而MSVC和clang则不同。
6.7.6.1(2):
要使两个指针类型兼容,两者都应具有相同的资格,并且两者都必须 是兼容类型的指针。
pda
和cpda
的类型具有相同的资格[根本不合格],因此问题是它们是否指向兼容类型,即double[3]
和{{1}兼容类型?
6.7.6.2(6):
要兼容两种数组类型,两者都应具有兼容的元素类型,如果 两个大小说明符都存在,并且是整数常量表达式,然后是两个大小 说明符应具有相同的常量值。如果在上下文中使用这两种数组类型 这需要它们兼容,如果两个大小说明符,它是未定义的行为 评估不等值。
所以问题是const double[3]
和double
是否是兼容的类型。
6.7.3(10):
要兼容两种合格类型,两者都应具有相同的合格版本 兼容类型;说明符或限定符列表中类型限定符的顺序 不会影响指定的类型。
我会说const double
和double
不兼容,所以gcc是对的。
初始化
const double
是可以的,因为6.5.16.1列表中的赋值约束(与初始化相关)
左操作数具有原子,限定或非限定指针类型,并且(考虑到 两个操作数都是左值操作数在左值转换后的类型 指向兼容类型的限定或非限定版本的指针,以及指向的类型 左边的所有限定符都是右边所指示的类型;
作为可接受的情况之一。 double const * cpd = pd;
和cpd
都指向pd
的限定版本,左操作数的目标包含权限所有的限定符(还有一个,double
)。
但是,const
和double*
类型不兼容,因此
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中则不行。