为什么int*[]衰减到int**而不是int [] []?

Me *_*d I 34 c++

我试图理解类型衰变的本质.例如,我们都知道数组在特定上下文中衰减为指针.我的尝试是了解如何int[]等同于int*二维数组如何与预期的指针类型不对应.这是一个测试用例:

std::is_same<int*, std::decay<int[]>::type>::value; // true
Run Code Online (Sandbox Code Playgroud)

这会按预期返回true,但这不会:

std::is_same<int**, std::decay<int[][1]>::type>::value; // false
Run Code Online (Sandbox Code Playgroud)

为什么这不是真的?我终于找到了一种让它返回true的方法,那就是让第一个维度成为一个指针:

std::is_same<int**, std::decay<int*[]>::type>::value; // true
Run Code Online (Sandbox Code Playgroud)

对于任何带指针的类型,断言都适用,但最后一个是数组.例如(int***[] == int****; // true).

我可以解释为什么会这样吗?为什么数组类型不符合预期的指针类型?

Oli*_*rth 62

为什么int*[]腐烂int**而不是int[][]

因为用它做指针运算是不可能的.

例如,int p[5][4]表示一个(长度为4的数组int)的数组.没有涉及指针,它只是一个连续的大小内存块5*4*sizeof(int).当你要求一个特定的元素时,例如int a = p[i][j],编译器真的这样做:

char *tmp = (char *)p           // Work in units of bytes (char)
          + i * sizeof(int[4])  // Offset for outer dimension (int[4] is a type)
          + j * sizeof(int);    // Offset for inner dimension
int a = *(int *)tmp;            // Back to the contained type, and dereference
Run Code Online (Sandbox Code Playgroud)

显然,它只能这样做,因为它知道"内部"维度的大小.施放到int (*)[4]保留此信息; 它是指向(长度为4的数组int)的指针.但是,一个int ** ; 它只是指向(指向int)的指针.

有关此问题的另一个内容,请参阅C FAQ的以下部分:

(这完全是针对C的,但这种行为在C++中基本没有变化.)


sup*_*cat 10

C并非真正"设计"为一种语言; 相反,随着需求的增加添加了功能,努力不破坏早期的代码.在开发C的时代,这种渐进式方法是一件好事,因为它意味着在大多数情况下,开发人员可以在语言可能需要做的所有事情都得到解决之前从早期的语言改进中获益.不幸的是,数组和指针处理方式的演变导致了各种各样的规则,这些规则在回想起来是不幸的.

在今天的C语言中,存在一个相当实质的类型系统,变量具有明确定义的类型,但事情并非总是如此.宣言char arr[8]; 将在当前范围内分配8个字节,并arr指向它们中的第一个.编译器不会知道它arr代表一个数组 - 它将代表一个char指针,就像任何其他char*.根据我的理解,如果一个人宣称char arr1[8], arr2[8];,该陈述arr1 = arr2;将是完全合法的,在概念上有点等同char *st1 = "foo, *st2 = "bar"; st1 = st2;,但几乎总是代表一个错误.

数组分解为指针的规则源于数组和指针实际上是同一个东西的时间.从那以后,数组已经被认为是一种独特的类型,但是语言需要保持与它们不存在的日子完全兼容.在制定规则时,如何处理二维数组的问题不是问题,因为没有这样的事情.人们可以做类似的事情char foo[20]; char *bar[4]; int i; for (i=0; i<4; i++) bar[i] = foo + (i*5);然后bar[x][y]以与现在使用二维数组相同的方式使用,但是编译器不会以这种方式查看事物 - 它只是bar看作指针的指针.如果一个人想让foo [1]指向与foo [2]完全不同的某个地方,那么人们可以完全合法地这样做.

当两个二维数组被添加到C时,没有必要保持与声明二维数组的早期代码的兼容性,因为没有任何.虽然可以指定char bar[4][5];生成相当于使用的内容的代码foo[20],在这种情况下a char[][]可以作为a使用char**,但有人认为,就像分配数组变量一样,99%的时间都是错误的,如果这是合法的,那么也会重新分配数组行.因此,C中的数组被识别为不同的类型,它们自己的规则有点奇怪,但它们就是它们.


Naw*_*waz 7

因为int[M][N]int**不兼容的类型.

但是,int[M][N]可以衰变成int (*)[N]类型.所以以下内容:

std::is_same<int(*)[1], std::decay<int[1][1]>::type>::value;
Run Code Online (Sandbox Code Playgroud)

应该给你true.