我了解不支持按成员分配数组,因此以下操作将不起作用:
int num1[3] = {1,2,3};
int num2[3];
num2 = num1; // "error: invalid array assignment"
我只是接受了这个事实,认为该语言的目的是提供一个开放式框架,并让用户决定如何实现诸如数组复制之类的事情。
但是,以下内容确实有效:
struct myStruct { int num[3]; };
struct myStruct struct1 = {{1,2,3}};
struct myStruct struct2;
struct2 = struct1;
数组 num[3]
从其在 struct1
中的实例按成员分配到其在 struct2
中的实例。
为什么结构支持按成员赋值数组,但通常不支持?
编辑:Roger Pate在话题中的评论std::string in struct - Copy/assignment issues?似乎指出了答案的大致方向,但我自己还不足以确认。
edit 2:许多优秀的回复。我选择 Luther Blissett 是因为我主要想知道行为背后的哲学或历史基本原理,但是 James McNellis 对相关规范文档的引用也很有用.
最佳答案
这是我的看法:
C 语言的发展提供了一些关于 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 试图用结构类型扩展 B 时,这引起了麻烦。他希望数组成为结构的一部分,就像今天在 C 中一样:
struct {
int inumber;
char name[14];
};
但是使用 B,BCPL 将数组作为指针的概念,这将需要 name
字段包含一个指针,该指针必须在运行时初始化到内存结构中 14 个字节的区域。初始化/布局问题最终通过对数组进行特殊处理来解决:编译器将跟踪数组在结构中、堆栈中的位置等,实际上不需要指向数据的指针来实现,除非在涉及数组的表达式中。这种处理使得几乎所有 B 代码仍然可以运行,并且是 “如果你查看它们,数组就会转换为指针” 规则的来源。这是一个兼容性 hack,结果非常方便,因为它允许开放大小的数组等。
下面是我对数组不能赋值的猜测:因为数组是 B 中的指针,你可以简单地写:
auto V[10];
V=V+5;
rebase 一个“数组”。这现在毫无意义,因为数组变量的基数不再是左值。所以这个赋值是不允许的,这有助于捕获少数在声明的数组上执行此 rebase 的程序。。然后这个概念就陷入了困境:由于数组从未被设计为 C 类型系统的一等公民,它们大多被视为特殊的野兽,如果你使用它们就会变成指针。从某种角度来看(忽略了 C 数组是拙劣的 hack),不允许数组赋值仍然有一定的意义:开放数组或数组函数参数被视为没有大小信息的指针。编译器没有为它们生成数组赋值的信息,并且出于兼容性原因需要指针赋值。为已声明的数组引入数组赋值会通过虚假赋值(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 修订版添加了结构赋值 (http://cm.bell-labs.com/cm/cs/who/dmr/cchanges.pdf) 时,这并没有改变。尽管记录在 C 中是不同的类型,但在早期的 K&R C 中不可能对它们进行分配。您必须使用 memcpy 按成员方式复制它们,并且您只能将指向它们的指针作为函数参数传递。赋值(和参数传递)现在被简单地定义为结构原始内存的 memcpy,并且由于这不会破坏现有代码,因此很容易被采用。作为一个意想不到的副作用,这隐含地引入了某种数组赋值,但这发生在结构内部的某个地方,所以这并不能真正引入数组使用方式的问题。
关于c++ - 为什么 C 和 C++ 支持结构内数组的成员赋值,但通常不支持?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64698678/