一维访问多维数组:行为是否明确? [英] One-dimensional access to a multidimensional array: is it well-defined behaviour?
问题描述
我想我们都同意,通过以一维方式取消引用(可能是偏移的)指向其第一个元素的指针来访问真正的多维数组被认为是惯用的C,例如:
I imagine we all agree that it is considered idiomatic C to access a true multidimensional array by dereferencing a (possibly offset) pointer to its first element in a one-dimensional fashion, e.g.:
void clearBottomRightElement(int *array, int M, int N)
{
array[M*N-1] = 0; // Pretend the array is one-dimensional
}
int mtx[5][3];
...
clearBottomRightElement(&mtx[0][0], 5, 3);
但是,我内在的语言律师需要说服这实际上是定义明确的C!特别是:
However, the language-lawyer in me needs convincing that this is actually well-defined C! In particular:
-
是否保证编译器不会在中间添加填充符?
mtx[0][2]
和mtx[1][0]
?
通常,未定义从数组末尾索引(末尾除外)的索引(C99,6.5.6/8).因此,以下内容显然是不确定的:
Normally, indexing off the end of an array (other than one-past the end) is undefined (C99, 6.5.6/8). So the following is clearly undefined:
struct {
int row[3]; // The object in question is an int[3]
int other[10];
} foo;
int *p = &foo.row[7]; // ERROR: A crude attempt to get &foo.other[4];
因此,根据相同的规则,人们希望以下内容未定义:
So by the same rule, one would expect the following to be undefined:
int mtx[5][3];
int (*row)[3] = &mtx[0]; // The object in question is still an int[3]
int *p = &(*row)[7]; // Why is this any better?
那为什么要定义它?
int mtx[5][3];
int *p = &(&mtx[0][0])[7];
那么C标准的哪一部分明确允许这样做? (为讨论起见,假设 c99 的问题.)
So what part of the C standard explicitly permits this? (Let's assume c99 for the sake of discussion.)
编辑
请注意,我毫无疑问在所有编译器中都能正常工作.我要查询的是标准是否明确允许这样做.
Note that I have no doubt that this works fine in all compilers. What I'm querying is whether this is explicitly permitted by the standard.
推荐答案
要进行这种访问的唯一障碍是,不允许类型为int [5][3]
和int [15]
的对象彼此别名.因此,如果编译器意识到类型为int *
的指针指向前者的int [3]
数组之一,则可能会施加数组范围限制,从而阻止访问该int [3]
数组之外的任何内容.
The only obstacle to the kind of access you want to do is that objects of type int [5][3]
and int [15]
are not allowed to alias one another. Thus if the compiler is aware that a pointer of type int *
points into one of the int [3]
arrays of the former, it could impose array bounds restrictions that would prevent accessing anything outside that int [3]
array.
通过将所有内容放入同时包含int [5][3]
数组和int [15]
数组的联合体中,您也许可以解决此问题,但是我真的不清楚人们是否使用了联合黑客来进行类型处理实际上是定义明确的.这种情况的问题可能会稍微少一些,因为您不会对单个单元格进行类型操作,而只需对数组逻辑进行操作,但是我仍然不确定.
You might be able to get around this issue by putting everything inside a union that contains both the int [5][3]
array and the int [15]
array, but I'm really unclear on whether the union hacks people use for type-punning are actually well-defined. This case might be slightly less problematic since you would not be type-punning individual cells, only the array logic, but I'm still not sure.
应注意的一种特殊情况:如果您的类型是unsigned char
(或任何char
类型),则将多维数组作为一维数组进行访问将是一个很好的定义.这是因为unsigned char
与其重叠的一维数组已由标准明确定义为对象的表示形式",并固有地允许对其进行别名.
One special case that should be noted: if your type were unsigned char
(or any char
type), accessing the multi-dimensional array as a one-dimensional array would be perfectly well-defined. This is because the one-dimensional array of unsigned char
that overlaps it is explicitly defined by the standard as the "representation" of the object, and is inherently allowed to alias it.
这篇关于一维访问多维数组:行为是否明确?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!