赋值<指向常量数组的指针> = <指向数组的指针>:不兼容的指针

kot*_*moy 9 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
Run Code Online (Sandbox Code Playgroud)

gcc警告我

warning: initialization from incompatible pointer type [enabled by default]
Run Code Online (Sandbox Code Playgroud)

问题:这项任务有什么问题?是的,从技术上讲,这些是不同的类型,但我没有看到任何危险,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
Run Code Online (Sandbox Code Playgroud)

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

3)在这个例子中

double d = 1.;
double * pd = &d;
double * * ppd = &pd;
double const * * cppd = ppd;  // gcc: warning; MSVC: error
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

编辑:

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

Dan*_*her 7

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

6.7.6.1(2):

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

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

6.7.6.2(6):

For two array types to be compatible, both shall have compatible element types, and if both size specifiers are present, and are integer constant expressions, then both size specifiers shall have the same constant value. If the two array types are used in a context which requires them to be compatible, it is undefined behavior if the two size specifiers evaluate to unequal values.

So the question is whether double and const double are compatible types.

6.7.3 (10):

For two qualified types to be compatible, both shall have the identically qualified version of a compatible type; the order of type qualifiers within a list of specifiers or qualifiers does not affect the specified type.

I would say that makes double and const double not compatible, so gcc is right.

The initialisation

double const * cpd = pd;
Run Code Online (Sandbox Code Playgroud)

is okay because the constraints of assignment (which are relevant for initialisation) in 6.5.16.1 list

the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;

as one of the admissible situations. cpd and pd both point to qualified versions of double, and the left operand's target has all qualifiers that the right has (and one more, const).

However, the types double* and const double* are not compatible, hence

double const * * cppd = ppd;
Run Code Online (Sandbox Code Playgroud)

is again invalid, and requires a diagnostic message.

  • 不,虽然指针类型不兼容,但6.5.16.1明确允许将`double*`赋值给`const double*`,参见附加. (2认同)

oua*_*uah 3

gcc就在这里,并且需要在 C 中进行诊断。

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

基本上,您试图将一个类型的对象分配T1给一个类型的对象T2(简单分配的约束适用于初始化)。

其中是指向 的数组的T1指针。NT

AndT2是一个指向 数组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
Run Code Online (Sandbox Code Playgroud)

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