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()
{
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++中引入了一种可以允许用户重载结构体赋值操作运算,那么我们就可以根据语义重载赋值操作。
数组是二等公民
二等公民在维基百科上的解释是:
二等公民不是一个正式的术语,用来描述一个社会体系内对一部分人的歧视或对外来人口的政治限制,即使他们作为一个公民或合法居民的地位。 二等公民虽然不一定是奴隶或罪犯,但他们只享有有限的合法权利、公民权利和经济机会,并经常受到虐待或忽视。法律无视二等公民,不向他们提供保护,甚至在制订法律时可能会根本不考虑他们的利益。划分出二等公民的行为,普遍被视为一种侵犯人权的行为。 典型的二等公民所面临的障碍包括但不仅限于(缺乏或丧失表决权):权利被剥夺,限制民事或军事服务(不包括任何情况下的征兵),以及限制,语言,宗教,教育,行动和结社的自由,武器的所有权,婚姻,性别认同和表达,住房和财产所有权 。
从词条上解释可以看出二等公民与一等公民在权利上是有差别的,这个词很有意思作为计算机专业术语,其含义也有异曲同工之妙!同样我们看看维基百科对计算机的术语”first-class citizen"(一等公民)的定义,一般要满足以下几点,
- 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;
但是如果数组包装在结构体中,那么就能进行赋值了!相比之下,结构体可以作为函数参数和返回值,这就是一等公民的待遇!至于为什么数组必须是二等公民,这是有历史原因的,大家可以参考C 语言的发展史来看,有时间这块内容我再补上!
参考资料:
- 维基百科
- Stackoverflow
- International Standard ISO/IEC 9899
c语言结构体可以直接赋值的更多相关文章
- C语言中结构体变量之间赋值
近期,我阅读了某新员工小刘写的C语言代码,发现其对结构体变量之间的赋值不是非常熟悉. 对于两个同样类型的结构体变量,他均採用的是逐个成员变量直接赋值的形式.例如以下的代码演示样例: 如上代码所看到的, ...
- go语言基础之结构体比较和赋值
1.结构体比较和赋值 (同类型的结构体可以相互赋值) 示例: package main //必须有个main包 import "fmt" //定义一个结构体类型 type Stud ...
- iOS学习06C语言结构体
1.结构体的概述 在C语言中,结构体(struct)指的是一种数据结构,是C语言中构造类型的其中之一. 在实际应用中,我们通常需要由不同类型的数据来构成一个整体,比如学生这个整体可以由姓名.年龄.身高 ...
- 不可或缺 Windows Native (8) - C 语言: 结构体,共用体,枚举,类型定义符
[源码下载] 不可或缺 Windows Native (8) - C 语言: 结构体,共用体,枚举,类型定义符 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 结构体 ...
- Go语言结构体(struct)
Go 语言结构体 Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型. 结构体是由一系列具有相同类型或不同类型的数据构成的数据集合. 结构体表示一项记录,比如保存图 ...
- 将c语言的结构体定义变成对应的golang语言的结构体定义,并将golang语言结构体变量的指针传递给c语言,cast C struct to Go struct
https://groups.google.com/forum/#!topic/golang-nuts/JkvR4dQy9t4 https://golang.org/misc/cgo/gmp/gmp. ...
- Linux C语言结构体-学习笔记
Linux C语言结构体简介 前面学习了c语言的基本语法特性,本节进行更深入的学习. 预处理程序. 编译指令: 预处理, 宏定义, 建立自己的数据类型:结构体,联合体,动态数据结构 c语言表达式工具 ...
- C语言结构体初始化的四种方法(转载)
原文:https://blog.csdn.net/ericbar/article/details/79567108 定义 struct InitMember { int first: double s ...
- 06. Go 语言结构体
Go语言结构体(struct) Go 语言通过用自定义的方式形成新的类型,结构体是类型中带有成员的复合类型.Go 语言使用结构体和结构体成员来描述真实世界的实体和实体对应的各种属性. Go 语言中的类 ...
随机推荐
- [ActionScript 3.0] 创建倒影
package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Display ...
- MIT 黑科技:通过脑电波和手势控制机器人
简评:麻省理工黑科技,虽然现在能实现的操作还很简单,但前景(想象空间)非常巨大. 通常,控制机器人并不容易,常规手段就是编程.但是地球上从来不缺天马行空的科学家,今日 MIT 的计算机科学与人工智能实 ...
- nginx下重写隐藏index.php文件
location / { root /项目目录/; index index.php; if (-f $request_filename/index.php){ rewrite (.*) $1/inde ...
- dcoker做私有仓库
在官网上拉取私有仓库的镜像.(官网提供的镜像为:registry) docker pull registry 启动镜像,并且映射端口.(启动时加-p参数即可) docker -d -p 5000 ...
- pycharm下运行unittest的问题
环境: 系统:window7 64 软件:pycharm 版本:2016.3.2 问题描述: 使用unittest类的时候出现问题,问题截图如下 Pycharm 2016.2执行单元测试遇到如下问题: ...
- php fputcsv 读取不到中文文件、数据
string setlocale(constant,location) constant 必需.规定应该设置什么地区信息. 可用的常量: LC_ALL - 包括下面的所有选项 LC_COLLATE ...
- MySQL使用UNIQUE实现数据不重复插入
unique列在一个UNIQUE键上插入包含重复值的记录时,我们可以控制MySQL如何处理这种情况:使用IGNORE关键字或者ON DUPLICATE KEY UPDATE子句跳过INSERT.中断操 ...
- Django项目创建与管理
1.主题 这部分教程主要介绍如何通过Pycharm创建.管理.运行一个Django工程.对于Django模块的相关知识大家可以参考Python社区. 2.准备环境 Django版本为2.0或更高 Py ...
- 剑指offer——面试题23:链表中环的入口节点
函数: ListNode* MeetingNode(ListNode* pHead) { if(pHead==nullptr) return nullptr; ListNode* quickNode= ...
- cookie session token详解
cookie session token详解 转自:http://www.cnblogs.com/moyand/ 发展史 1.很久很久以前,Web 基本上就是文档的浏览而已, 既然是浏览,作为服务器, ...