我知道不支持按成员分配数组,因此以下操作将不起作用:

int num1[3] = {1,2,3};
int num2[3];
num2 = num1; // "error: invalid array assignment"

我只是接受了这一事实,认为该语言的目的是提供一个开放式框架,并让用户决定如何实现某种功能,比如复制array.

但是,以下方法确实有效:

struct myStruct { int num[3]; };
struct myStruct struct1 = {{1,2,3}};
struct myStruct struct2;
struct2 = struct1;

数组num[3]以成员方式从struct1中的实例分配到struct2中的实例中.

为什么 struct 支持按成员分配数组,但一般不支持?

edit:Roger Pate在线程std::string in struct - Copy/assignment issues?中的 comments 似乎指向了答案的大致方向,但我自己知道的还不足以证实这一点.

edit 2:很多优秀的回答.我 Select Luther Blissett是因为我主要想知道这种行为背后的哲学或历史原理,但James McNellis对相关规范文档的引用也很有用.

推荐答案

以下是我的看法:

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 内部的某个地方,因此这并不能真正引入数组使用方式的问题.

C++相关问答推荐

如何将一个enum类型类型转换为另一个类型?

为什么复合文字(C99)的返回会生成更多的汇编代码?

特定闪存扇区的内存别名

X86/x64上的SIGSEGV,由于原始内存访问和C中的DS寄存器之间的冲突,在Linux上用TCC编译为JIT引擎

试图从CSV文件中获取双精度值,但在C++中始终为空

Setenv在c编程中的用法?

使用错误的命令执行程序

函数的限制限定指针参数允许优化调用方函数吗?

无法在OpenGL上绘制三角形

如何使用libgpio(d)为Raspberry Pi编译C程序?

错误...的多个定义(&Q)首先在这里定义&

C语言中MPI发送接收字符串时出现的分段错误

将回调/基于事件的C API转换为非回调API

pthread_create的用法

从CentOS 7到Raspberry PI 2B的交叉编译-无法让LIBC和System Include标头一起工作

为什么GCC 13没有显示正确的二进制表示法?

在我的函数中实现va_arg的问题

与指针的原始C数组或C++向量<;向量<;双>>;

UEFI 应用程序中的计时器回调仅在 AMI BIOS 中挂起

当循环变量在溢出时未定义时,可以进行哪些优化?