C:结构体复制与赋值、浅拷贝与深拷贝相关问题 | 您所在的位置:网站首页 › c语言struct数组 › C:结构体复制与赋值、浅拷贝与深拷贝相关问题 |
先思考: 结构体能否用“=”号直接赋值? 如何理解结构体的浅拷贝与深拷贝? 结构体“=”号赋值与“malloc”赋值哪个更好?效率更高? 直接上代码! 1.结构体能否用“=”号直接赋值?编写C代码: vi struck_assign.c内容如下: #include struct Foo { char a; int b; double c; }foo1, foo2; //define two structs with three different fields void struct_assign(void) { foo2 = foo1; //structure directly assignment } int main() { foo1.a = 'a'; foo1.b = 1; foo1.c = 3.14; struct_assign(); printf("%c %d %lf\n", foo2.a, foo2.b, foo2.c); return 0; }可以从结果上看出,结构体直接赋值在C语言下是可行的。 汇编C代码: gcc -S struck_assign.c cat struck_assign.s我们看看struct_assign()函数的汇编实现,从而从底层看看C语言是如何实现两个结构体之间的赋值操作的: struct_assign: ... movq %rsp, %rbp .cfi_def_cfa_register 6 movq foo1(%rip), %rax movq foo1+8(%rip), %rdx movq %rax, foo2(%rip) movq %rdx, foo2+8(%rip) nop这段汇编比较简单,由于结构体的对齐的特性,sizeof(srtruct Foo)=16,通过四次movl操作将foo1的结构体内容拷贝到结构体foo2中。从汇编上看出,结构体赋值,采用的类似于memcpy这种形式,而不是逐个字段的拷贝。 2.如何理解结构体的浅拷贝与深拷贝?如果结构体中含有其它复杂数据类型呢,例如数组、指针、结构体等,从上面的汇编实现可以看出,只要两个结构体类型相同,就可以实现赋值,如下例: #include #include struct Foo { char a; int b; double c; char *p_d; }foo1, foo2; void struct_shallow_copy(void) { foo2 = foo1; //structure directly assignment } int main() { char *d = (char *) malloc (4*sizeof(char)); d[0] = 'b'; d[1] = 'c'; d[2] = 'd'; d[3] = '\0'; foo1.a = 'a'; foo1.b = 1; foo1.c = 3.14; foo1.p_d = d; struct_shallow_copy(); printf("%c %d %lf %s\n", foo2.a, foo2.b, foo2.c, foo2.p_d); printf("%#x %#x\n", foo1.p_d, foo2.p_d); return 0; }可以看出结果和我们想象的是一样的。再次验证结构体的赋值,是直接结构体的内存的拷贝!但正是这个问题,如上面的实例,foo1 和 foo2 中p_d 指针都是指向我们申请的一块大小为4个字节的内存区域,这里注意的是,结构体的拷贝只是浅拷贝,即指针p_d的赋值并不会导致再申请一块内存区域,让foo2的p_d指向它。那么,如果释放掉foo1中的p_d指向的内存,此时foo2中p_d变成野指针,这是对foo2的p_d操作就会出现一些不可预见的问题! 那如何做成深拷贝?如下代码: #include #include #include struct Foo { char a; int b; double c; char *p_d; }foo1, foo2; void struct_deep_copy(void) { foo2.a = foo1.a; foo2.b = foo1.b; foo2.c = foo1.c; foo2.p_d = (char *) malloc (4*sizeof(char)); strcpy(foo2.p_d,foo1.p_d); //Deep copy } int main() { char *d = (char *) malloc (4*sizeof(char)); d[0] = 'b'; d[1] = 'c'; d[2] = 'd'; d[3] = '\0'; foo1.a = 'a'; foo1.b = 1; foo1.c = 3.14; foo1.p_d = d; struct_deep_copy(); printf("%c %d %lf %s\n", foo2.a, foo2.b, foo2.c, foo2.p_d); printf("%#x %#x\n", foo1.p_d, foo2.p_d); return 0; }根据上述的结果,得出结论: 浅拷贝是将一个结构体里面的值完全赋给另一个结构体,当结构体中含有指针变量时,浅拷贝只会拷贝指针所指向的空间地址值,不会自动分配内存(即原指针与拷贝指针都指向同一块内存,一不小心可能犯对同一块动态内存进行多次释放的错误) 深拷贝可以自动为指针分配内存(即原指针与拷贝指针所指向的内存空间不同,只是内存中存的值相同,可以避免对同一块动态内存进行多次释放的错误) 如果结构体内无指针变量,浅拷贝与深拷贝效果相同 3.结构体“=”号赋值与“memcpy”赋值哪个更好?效率更高?上代码直接比较,看下汇编阶段,哪个流程更少点。 #include #include struct Foo { char a; int b; double c; char *d; }foo1, foo2, foo3; //define two structs with three different fields void struct_assign(void) { foo2 = foo1; //structure directly assignment } void struct_copy(void) { memcpy(&foo3,&foo1,sizeof(struct Foo)); //Structure directly copy } int main() { foo1.a = 'a'; foo1.b = 1; foo1.c = 3.14; foo1.d = "efg"; struct_assign(); printf("%c %d %lf %s\n", foo2.a, foo2.b, foo2.c, foo2.d); printf("%p\n", foo2.d); struct_copy(); printf("%c %d %lf %s\n", foo3.a, foo3.b, foo3.c, foo3.d); printf("%p\n", foo3.d); return 0; }编译汇编如下: struct_assign: ... movq %rsp, %rbp .cfi_def_cfa_register 6 movq foo1(%rip), %rax movq %rax, foo2(%rip) movq foo1+8(%rip), %rax movq %rax, foo2+8(%rip) movq foo1+16(%rip), %rax movq %rax, foo2+16(%rip) nop struct_copy: ... movq %rsp, %rbp .cfi_def_cfa_register 6 movq foo1(%rip), %rax movq %rax, foo3(%rip) movq foo1+8(%rip), %rax movq %rax, foo3+8(%rip) movq foo1+16(%rip), %rax movq %rax, foo3+16(%rip) nop根据上述结果,得出结论: 两种实现,从汇编层面是一致的! 结构体赋值实现也是调用的memcpy。本质上效率应该是差不多的! Ps:比较效率的话最好能够懂一点简单的汇编代码,看看就明白了。 参考: https://blog.csdn.net/qq_33706673/article/details/85253536 https://bbs.csdn.net/topics/310074713 https://blog.csdn.net/qq_34013719/article/details/109061140 收录于: 嵌入式软件/BSP开发工程师/Linux驱动工程师/C语言经典笔试面试题大全 |
CopyRight 2018-2019 实验室设备网 版权所有 |