问题描述
我想我们都同意通过以一维方式取消引用(可能偏移)指向其第一个元素的指针来访问真正的多维数组被认为是惯用的 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.
这篇关于对多维数组的一维访问:它是定义明确的行为吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!