我理解不支持成员分配数组,因此以下方法不起作用:
int num1[3] = {1,2,3};
int num2[3];
num2 = num1; // "error: invalid array assignment"
我只是接受了这个事实,认为语言的目的是提供一个开放式框架,并让用户决定如何实现诸如复制数组之类的东西 .
但是,以下工作正常:
struct myStruct {int num[3];};
myStruct struct1={{1,2,3}};
myStruct struct2;
struct2 = struct1;
数组 num[3]
是成员方式,从 struct1
中的实例分配到 struct2
中的实例 .
为什么结构支持成员方式的数组,但一般情况下不支持?
edit : Roger Pate 在帖子中的评论std::string in struct - Copy/assignment issues?似乎指向答案的大致方向,但我不知道自己确认 .
edit 2 :很多出色的回应 . 我之所以选择_221760,是因为我主要想知道这种行为背后的哲学或历史原理,但 James McNellis 对相关规范文档的引用也很有用 .
4 回答
我知道,每个回答的人都是C / C的专家 . 但我想,这是主要原因 .
num2 = num1;
在这里,您尝试更改阵列的基址,这是不允许的 .
当然,struct2 = struct1;
这里,对象struct1被分配给另一个对象 .
关于赋值运算符,C标准如下(C03§5.17/ 1):
数组不是可修改的左值 .
但是,特别定义了对类类型对象的赋值(§5.17/ 4):
因此,我们期待查看类的隐式声明的复制赋值运算符(§12.8/ 13):
因此,对于类类型对象,正确复制数组 . 请注意,如果您提供用户声明的复制赋值运算符,则无法利用此功能,并且您必须逐个元素地复制数组 .
推理在C(C99§6.5.16/ 2)中类似:
§6.3.2.1/ 1:
在C中,赋值比C(§6.5.16.1/ 2)简单得多:
对于struct-type对象的赋值,左右操作数必须具有相同的类型,因此右操作数的值只是复制到左操作数中 .
在这个链接:http://www2.research.att.com/~bs/bs_faq2.html有一个关于数组赋值的部分:
数组的两个基本问题是
数组不知道自己的大小
数组的名称在最轻微的激发时转换为指向其第一个元素的指针
我认为这是数组和结构之间的根本区别 . 数组变量是具有有限自我知识的低级数据元素 . 从根本上说,它是一块记忆和一种索引的方式 .
因此,编译器无法区分int a [10]和int b [20]之间的区别 .
然而,结构不具有相同的模糊性 .
这是我的看法:
C语言的开发提供了对C中数组类型演变的一些见解:
我将尝试概述数组的事情:
C的先行者B和BCPL没有明显的数组类型,声明如下:
将V声明为一个(无类型)指针,该指针被初始化为指向未使用的10 "words"内存区域 . B已使用
*
进行指针解除引用并使用[]
简写符号,*(V+i)
表示V[i]
,就像今天的C / C.但是,V
不是一个数组,它仍然是一个必须指向某个内存的指针 . 当Dennis Ritchie试图用结构类型扩展B时,这会引起麻烦 . 他希望数组成为结构的一部分,就像今天的C一样:但是使用B,BCPL数组作为指针的概念,这将要求
name
字段包含一个指针,该指针必须在运行时初始化为结构中14字节的内存区域 . 初始化/布局问题最终通过为数组提供特殊处理来解决:编译器将跟踪数组在结构中,堆栈上的位置等,而实际上不需要指向数据的指针来实现,除了涉及数组的表达式 . 这种处理方法几乎允许所有B代码仍然运行,并且是该代码的来源"arrays convert to pointer if you look at them"规则 . 这是一个兼容性的黑客,结果非常方便,因为它允许开放大小的阵列等 .这里是我的猜测为什么不能分配数组:由于数组是B中的指针,你可以简单地写:
改变"array" . 这现在毫无意义,因为数组变量的基数不再是左值 . 所以这个分配是不允许的,这有助于捕获在声明的数组上进行这种变基的少数程序 . 然后这个概念陷入困境:由于数组从未设计为C类型系统的第一类城市化,它们大多被视为特殊的野兽,如果你使用它们就会成为指针 . 从某个角度来看(忽略了C阵列是一个拙劣的黑客攻击),禁止数组赋值仍然有一定意义:开放数组或数组函数参数被视为没有大小信息的指针 . 编译器没有为它们生成数组赋值的信息,并且出于兼容性原因需要指针赋值 . 为声明的数组引入数组赋值会引入错误,虽然是虚假的分配(是a = ba指针赋值还是元素副本?)和其他麻烦(如何通过值传递数组?)而不实际解决问题 - 只需制作一切用memcpy显式!
当1978年的C修订版增加了结构分配(http://cm.bell-labs.com/cm/cs/who/dmr/cchanges.pdf)时,这并没有改变 . 即使记录是C中的不同类型,也不可能在早期的K&R C中分配它们 . 您必须使用memcpy将它们成员复制,并且您只能将指针作为函数参数传递给它们 . Assigment(和参数传递)现在简单地定义为struct 's raw memory and since this couldn't的memcpy,它可以打破现有的代码 . 作为一种意想不到的副作用,这隐含地引入了某种类型的数组赋值,但是它在结构中的某处发生了,所以这不能真正引入数组使用方式的问题 .