c语⾔结构体可以直接赋值
结构体直接赋值的实现
下⾯是⼀个实例:
#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()
{
sizeof结构体大小
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,通过四次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++中引⼊了⼀种可以允许⽤户重载结构体赋值操作运算,那么我们就可以根据语义重载赋值操作。
数组是⼆等公民
在上的解释是:
⼆等公民不是⼀个正式的术语,⽤来描述⼀个社会体系内对⼀部分⼈的歧视或对外来⼈⼝的政治限制,即使他们作为⼀个公民或合法居民的地位。⼆等公民虽然不⼀定是奴⾪或罪犯,但他们只享有有限的合法权利、公民权利和经济机会,并经常受到虐待或忽视。法律⽆视⼆等公民,不向他们提供保护,甚⾄在制订法律时可能会根本不考虑他们的利益。划分出⼆等公民的⾏为,普遍被视为⼀种侵犯⼈权的⾏为。典型的⼆等公民所⾯临的障碍包括但不仅限于(缺乏或丧失表决权):权利被剥夺,限制民事或军事服务(不包括任何情况下的征兵),以及限制,语⾔,宗教,教育,⾏动和结社的⾃由,武器的所有
权,婚姻,性别认同和表达,住房和财产所有权。
从词条上解释可以看出⼆等公民与⼀等公民在权利上是有差别的,这个词很有意思作为计算机专业术语,其含义也有异曲同⼯之妙!同样我们看看对计算机的术语”"(⼀等公民)的定义,⼀般要满⾜以下⼏点,
can be stored in variables and data structures
can be passed as a parameter to a subroutine
can be returned as the result of a subroutine
can be constructed at run-time
has intrinsic identity (independent of any given name)
对⽐着上⾯的定义来看C语⾔数组,数组作为⼀个函数的参数传递时,退化成⼀个指针; 同时,数组⽆法作为函数的返回值; 也许让数组更不服⽓的是,数组之间不能直接赋值操作,如下⾯的操作就是⾮法的:
int a[10];
int b[10];
a = b;
但是如果数组包装在结构体中,那么就能进⾏赋值了!相⽐之下,结构体可以作为函数参数和返回值,这就是⼀等公民的待遇!⾄于为什么数组必须是⼆等公民,这是有历史原因的,⼤家可以参考来看。