结构体直接赋值条件

本文探讨了C语言中结构体的直接赋值操作,指出只要结构体类型相同,就可以直接赋值,并通过实例和汇编代码解释了这一过程。然而,当结构体包含复杂数据类型如指针时,这种赋值是浅拷贝,可能导致指针指向的内存区域问题。文章强调了理解结构体赋值的内存拷贝本质,以及在C++中如何通过重载赋值操作符来处理深拷贝问题。
摘要由CSDN通过智能技术生成

最近在阅读代码的时候发现有直接使用结构体赋值的地方,比较疑惑,在最初观念里结构体赋值一般通过memcpy或者strcpy实现赋值,网上搜了下,发现结构体赋值只能在相同的结构体类型中才可以

下面是一个实例:

#include <stdio.h>

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;   
}
我在Ubuntu 13.04下使用gcc 4.7.3 编译运行得到的结果,如下所示:

guohl@guohailin:~/Documents/c$ gcc struct_test1.c -o struct_test1
guohl@guohailin:~/Documents/c$ ./struct_test1 
a 1 3.140000
可以从结果上看出,只要两个结构体类型相同,结构体直接赋值在C语言下是可行的

下面是struct_assign()函数的汇编实现,从而从底层看看C语言是如何实现两个结构体之间的赋值操作的:

struct_assign:
    pushl   %ebp
    movl    %esp, %ebp
    movl    foo1, %eax
    movl    %eax, foo2      //copy the first 4 bytes from foo1 to foo2
    movl    foo1+4, %eax
    movl    %eax, foo2+4    //copy the second 4 bytes from foo1 to foo2       
    movl    foo1+8, %eax
    movl    %eax, foo2+8    //copy the third 4 bytes from foo1 to foo2  
    movl    foo1+12, %eax
    movl    %eax, foo2+12   //copy the forth 4 bytes from foo1 to foo2  
    popl    %ebp
    ret

这段汇编比较简单,由于结构体的对齐的特性,sizeof(srtruct Foo)=16,通过4次movl操作将foo1的结构体内容拷贝到结构体foo2中。从汇编上看出,结构体赋值,采用的类似于memcpy这种形式,而不是逐个字段的拷贝

复杂结构体的赋值
如果结构体中含有其它复杂数据类型呢,例如数组、指针、结构体等,从上面的汇编实现可以看出,只要两个结构体类型相同,就可以实现赋值

如下例:

#include <stdio.h>

struct Foo {
    int n;
    double d[2];
    char *p_c;
}foo1, foo2;

int main()
{
    char *c = (char *) malloc (4*sizeof(char));
    c[0] = 'a'; c[1] = 'b'; c[2] = 'c'; c[3] = '\0';

    foo1.n = 1;
    foo1.d[0] = 2; foo1.d[1] = 3;
    foo1.p_c = c;

    foo2 = foo1;     //assign foo1 to foo2

    printf("%d %lf %lf %s\n", foo2.n, foo2.d[0], foo2.d[1], foo2.p_c);

    return 0;
}

运行结果如下:

guohl@guohailin:~/Documents/c$ gcc struct_test2.c -o struct_test2
guohl@guohailin:~/Documents/c$ ./struct_test2
1 2.000000 3.000000 abc
可以看出结果和我们想象的是一样的。再次验证结构体的赋值,是直接结构体的内存的拷贝!但正是这个问题,如上面的实例,foo1 和 foo2 中p_c 指针都是指向我们申请的一块大小为4个字节的内存区域,这里注意的是,结构体的拷贝只是浅拷贝,即指针p_c的赋值并不会导致再申请一块内存区域,让foo2的p_c指向它。那么,如果释放掉foo1中的p_c指向的内存,此时foo2中p_c变成野指针,这是对foo2的p_c操作就会出现一些不可预见的问题!在C++中引入了一种可以允许用户重载结构体赋值操作运算,那么我们就可以根据语义重载赋值操作。

 

参考: 

https://blog.csdn.net/hazir/article/details/9429017

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值