以下是我的看法:
The Development of the C Language提供了对C:中数组类型演变的一些见解:
我将试着概述一下数组的内容:
C的前身B和BCPL没有不同的数组类型,声明如下:
auto V[10] (B)
or
let V = vec 10 (BCPL)
将V声明为(非类型化)指针,该指针初始化为指向内存中10个"字"的未使用区域.B已经使用*
来进行指针解引用,并且使用[]
简写符号,*(V+i)
表示V[i]
,就像今天的C/C++一样.然而,V
不是一个数组,它仍然是一个指针,必须指向一些内存.当Dennis Ritchie试图用 struct 类型扩展B时,这就造成了麻烦.他希望数组成为 struct 的一部分,就像今天的C一样:
struct {
int inumber;
char name[14];
};
但是如果使用B,BCPL概念,即数组作为指针,则需要name
字段包含一个指针,该指针必须是initialized at runtime,指向 struct 中14字节的内存区域.通过对数组进行特殊处理,初始化/布局问题最终得以解决:编译器将跟踪数组在 struct 、堆栈等中的位置,而不需要实际实现指向数据的指针,但在涉及数组的表达式中除外.这种处理允许几乎所有的B代码仍然运行,并且是"arrays convert to pointer if you look at them"规则的来源.这是一个兼容性攻击,结果证明非常方便,因为它允许开放大小的数组等.
下面是我猜想数组不能赋值的原因:因为数组在B中是指针,所以您可以简单地写成:
auto V[10];
V=V+5;
重新设置"数组"的基址.这现在毫无意义,因为数组变量的基不再是左值.因此,这种分配是不允许的,这有助于捕捉到少数几个实现了on declared arrays次重定的项目.然后这个概念就被卡住了:由于数组从来没有被设计成C类型系统的第一类城市化,它们大多被视为特殊的野兽,如果你使用它们,它们就会变成指针.从某种Angular 来看(忽略了C数组是一个拙劣的黑客),不允许数组赋值仍然有一定的意义:一个开放数组或数组函数参数被视为一个没有大小信息的指针.编译器没有为它们生成数组赋值的信息,并且出于兼容性原因需要指针赋值.为声明的数组引入数组赋值会引入错误,尽管存在虚假的赋值(a=b是指针赋值还是元素复制?)以及其他问题(如何通过值传递数组?)不需要真正解决问题——只需使用memcpy将所有内容都明确化!
/* Example how array assignment void make things even weirder in C/C++,
if we don't want to break existing code.
It's actually better to leave things as they are...
*/
typedef int vec[3];
void f(vec a, vec b)
{
vec x,y;
a=b; // pointer assignment
x=y; // NEW! element-wise assignment
a=x; // pointer assignment
x=a; // NEW! element-wise assignment
}
1978年C的修订版增加了 struct 赋值(http://cm.bell-labs.com/cm/cs/who/dmr/cchanges.pdf),这一点没有改变.尽管在C语言中记录了were种不同的类型,但在早期的K&;R C.必须使用memcpy以成员方式复制它们,并且只能将指针作为函数参数传递给它们.assignment(和参数传递)现在被简单地定义为 struct 的原始内存的memcpy,因为它不能 destruct 现有代码,所以很容易被apply.作为一个意外的副作用,这隐式地引入了某种数组赋值,但这发生在 struct 内部的某个地方,因此这并不能真正引入数组使用方式的问题.