9

当我编译这样的东西时

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++),它没有给出任何错误,也没有任何警告。我编辑了上面代码的注释

4

3 回答 3

7

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

6.7.6.1 (2):

对于要兼容的两种指针类型,两者都应具有相同的限定,并且都应是指向兼容类型的指针。

pda和的类型cpda是相同限定的[根本没有限定],所以问题是它们是否指向兼容类型,即是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 列表中的分配约束(与初始化相关)

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

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

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

double const * * cppd = ppd;

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

于 2013-06-15T11:24:13.943 回答
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是一个指向数组Nconst 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指针的限定版本。在 C 中,数组不能是常量:没有数组,只有元素数组。NTconstconst

于 2013-06-15T11:23:45.177 回答
1

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

于 2013-06-15T11:23:35.057 回答