可修改的左值为什么不能具有数组类型?

10
从C11标准(§6.3.2.1 左值,数组和函数指示符)中可知:
可修改左值是一个左值,它不具有数组类型,不具有不完全类型,不具有const限定类型,如果它是结构体或联合体,则不具有任何成员(包括所有包含的聚合体或联合体的递归成员或元素)具有const限定类型。
来自《C in a Nutshell》的描述如下:
可修改左值是一个左值,它没有声明为const限定符类型(请参阅第180页的“类型限定符”),并且不具有数组类型。
为什么可修改左值不能具有数组类型?
数组类型的对象在创建时就被初始化,因此不能再次赋值。对于可修改左值,允许再次分配新值,而这与数组类型的对象相反。因此,数组类型的对象不能作为可修改的左值。
一个数组类型的对象总是隐式的const吗?
是的,数组类型的对象被视为常量指针,因此不能用作可修改的左值。

3
您可以将可修改的左值赋值给它们,但不能直接将值赋给数组(只能赋值给数组元素),因此数组名不能是可修改的左值。 - Jonathan Leffler
在某些方面,函数名就像数组名;你肯定不能对函数名进行赋值 - 但你可以使用它来调用函数或初始化函数指针。'可修改的左值'的关键在于你可以在赋值中使用 lvalue = rvalue; - Jonathan Leffler
1
它是一个不可修改的左值。标准在§6.3.2.1的脚注64中提到了“rvalue”一次:有时所谓的“rvalue”在这个国际标准中被描述为“表达式的值”。 它也在引用之前的几个句子中指定了一个通用的左值:一个左值是一个表达式(具有除void以外的对象类型),它可能指示一个对象;(64)如果一个左值在评估时没有指示一个对象,那么其行为是未定义的。 脚注64还表示左值可以被认为代表一个对象的定位器值。 - Jonathan Leffler
没错,这是另一种看待问题的方式——函数不是对象(指向函数的指针也不是指向对象的指针,并且指向函数的指针不必转换为指向对象的指针等等)。使用注释有其原因——当您在注释中犯小错误时,它们不像答案那样被踩到。 - Jonathan Leffler
1
没有特别深刻的原因;这只是语言设计者做出的选择。很可能是因为分配数组可能具有任意高的成本,而他们不希望该成本“悄然累积”。但这只是猜测。您可以通过将它们作为结构体成员并分配那些左值来轻松地分配数组。 - Kerrek SB
显示剩余7条评论
1个回答

10
C语言的设计者决定不支持数组值赋值。在当时(20世纪70年代初),这似乎是个明智的决定——内存和处理器速度都非常有限,他们认为使a=b;使a和b都指向同一个数组比将a=b;用于将一个数组的内容复制到另一个数组中更常见。
实际上,这已经是常见用法:在B编程语言(C的前身)中,int a[10];的等价物实际上意味着分配一个指针和一个10个整数的块,并将指针指向10个整数的块。在B中,你实际上可以让数组“指向”其他地方。
C改变了数组定义的含义,只分配整数块;并添加了“The Rule”:当你在赋值表达式(以及大多数其他表达式)中使用数组的名称时,数组会被隐式转换为指向第一个元素的指针。因此,如果a是指针,b是数组,那么你仍然可以写a=b;来使a行为像b的别名。尽管你不能再有a=b;其中a是数组。
在1989年的第一个ANSI C标准中,他们添加了通过值复制结构体的能力(这在一些编译器中已经存在,但不是普遍的),其推论是,如果结构体包含数组,则数组将按值复制。但是,回头改变a=b;的含义以通过值复制数组已经太晚了,因为已经有太多的代码依赖于“The Rule”。
参考资料: The Development of the C Language - Dennis M. Ritchie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接