在C中将一个结构分配给另一个

shr*_*sva 134 c struct

你可以将一个结构的一个实例分配给另一个,如下所示:

struct Test t1;
struct Test t2;
t2 = t1;
Run Code Online (Sandbox Code Playgroud)

我看到它适用于简单的结构,它是否适用于复杂的结构?
编译器如何知道如何根据类型复制数据项,即区分int和字符串?

fab*_*ioM 138

如果结构属于同一类型,则为是.将其视为内存副本.

  • 请记住,没有深拷贝,指向内存不被复制. (70认同)
  • @Tim并发不再是分配内置类型(如整数和双精度)的问题 - 赋值也不是这些的原子操作. (16认同)
  • @Betlista你不能用free()释放内存,因为它们是自动变量:http://en.wikipedia.org/wiki/Automatic_variable (5认同)
  • 并发也是一个问题. (3认同)
  • 好的,如果创建了副本,我可以稍后用free()释放内存吗? (2认同)

小智 132

是的,结构支持赋值.但是,有一些问题:

struct S {
   char * p;
};

struct S s1, s2;
s1.p = malloc(100);
s2 = s1;
Run Code Online (Sandbox Code Playgroud)

现在两个结构的指针指向同一块内存 - 编译器不会复制指向的数据.现在很难知道哪个struct实例拥有数据.这就是C++发明用户可定义赋值运算符概念的原因 - 您可以编写特定代码来处理这种情况.

  • 为什么这被标记为垃圾邮件?有人失去了对鼠标的控制吗? (12认同)
  • 我提高了它,因为阅读它让我意识到我自己的答案中的错误/遗漏。 (2认同)
  • @rahmanisback anon对此主题的回答很明确:“编译器不会将指向__的数据复制到__数据中”。清楚地复制了“ struct”本身的数据。 (2认同)

小智 23

首先看一下这个例子:

下面给出了简单C程序的C代码

struct Foo {
    char a;
    int b;
    double c;
    } foo1,foo2;

void foo_assign(void)
{
    foo1 = foo2;
}
int main(/*char *argv[],int argc*/)
{
    foo_assign();
return 0;
}
Run Code Online (Sandbox Code Playgroud)

foo_assign()的等效ASM代码是

00401050 <_foo_assign>:
  401050:   55                      push   %ebp
  401051:   89 e5                   mov    %esp,%ebp
  401053:   a1 20 20 40 00          mov    0x402020,%eax
  401058:   a3 30 20 40 00          mov    %eax,0x402030
  40105d:   a1 24 20 40 00          mov    0x402024,%eax
  401062:   a3 34 20 40 00          mov    %eax,0x402034
  401067:   a1 28 20 40 00          mov    0x402028,%eax
  40106c:   a3 38 20 40 00          mov    %eax,0x402038
  401071:   a1 2c 20 40 00          mov    0x40202c,%eax
  401076:   a3 3c 20 40 00          mov    %eax,0x40203c
  40107b:   5d                      pop    %ebp
  40107c:   c3                      ret    
Run Code Online (Sandbox Code Playgroud)

正如您所看到的那样,赋值只是由汇编中的"mov"指令替换,赋值运算符只是意味着将数据从一个内存位置移动到另一个内存位置.赋值仅对结构的直接成员执行,并且在结构中具有复杂数据类型时将无法复制.这里COMPLEX意味着你不能指向列表的指针数组.

结构中的字符数组本身在大多数编译器中都不起作用,这是因为赋值只会尝试复制而不会将数据类型视为复杂类型.

  • 您能详细说明在什么情况下会失败,因为它似乎总是对我有用 (2认同)

Tho*_*nin 15

这是一个简单的副本,就像你一样memcpy()(事实上​​,一些编译器实际上会产生memcpy()对该代码的调用).C中没有"字符串",只有指向一堆字符的指针.如果您的源结构包含这样的指针,那么指针将被复制,而不是字符本身.

  • 好的,所以编译器将其翻译为“memcpy”,请参见此处:https://godbolt.org/z/nPxqWc - 但现在如果我传递相同的指针“a”和“b”,以及“*a = *b”被翻译为“memcpy”,这是未定义的行为,因为对于“memcpy”“内存区域不能重叠。” (引用自手册页)。那么编译器使用“memcpy”是错误的还是我写这样的赋值是错误的? (2认同)

Cli*_*ord 6

你的意思是"复杂",与复数有实部和虚部吗?这似乎不太可能,所以如果不是,你必须给出一个例子,因为"复杂"意味着没有任何具体的C语言.

您将获得该结构的直接内存副本; 这是否是你想要的取决于结构.例如,如果结构包含指针,则两个副本将指向相同的数据.这可能是也可能不是你想要的; 这取决于你的程序设计.

要执行"智能"副本(或"深度"副本),您需要实现一个函数来执行复制.如果结构本身包含也包含指针的指针和结构,并且可能指向这样的结构(可能就是"复杂"的意思),这可能很难实现,而且很难维护.简单的解决方案是使用C++并为每个结构或类实现复制构造函数和赋值运算符,然后每个都负责其自己的复制语义,您可以使用赋值语法,并且它更容易维护.