Linux C中结构体初始化
在阅读GNU/Linux内核代码时,我们会遇到一种特殊的结构初始化方式。该方式是某些C教材(如谭二版、K&R二版)中没有介绍过的。这种方式称为指定初始化(designated initializer)。下面我们看一个例子,Linux-2.6.x/drivers/usb/storage/usb.c中有这样一个结构体初始化项目:
static struct usb_driver
usb_storage_driver = {
.owner = THIS_MODULE,
.name = "usb-storage",
.probe = storage_probe,
.disconnect =
storage_disconnect,
.id_table =
storage_usb_ids,
};
乍一看,这与我们之前学过的结构体初始化差距甚远。其实这就是前面所说的指定初始化在Linux设备驱动程序中的一个应用,它源自ISO
C99标准。以下我摘录了C Primer
Plus第五版中相关章节的内容,从而就可以很好的理解2.6版内核采用这种方式的优势就在于由此初始化不必严格按照定义时的顺序。这带来了极大的灵活性,其更大的益处还有待大家在开发中结合自身的应用慢慢体会。
已知一个结构,定义如下
struct book {
char title[MAXTITL];
char author[MAXAUTL];
float value;
};
C99支持结构的指定初始化项目,其语法与数组的指定初始化项目近似。只是,结构的指定初始化项目使用点运算符和成员名(而不是方括号和索引值)来标识具体的元素。例如,只初始化book结构的成员value,可以这样做:
struct book surprise = { .value
= 10.99 };
可以按照任意的顺序使用指定初始化项目:
struct book gift = {
.value = 25.99,
.author = "James
Broadfool",
.title = "Rue for the
Toad"};
正像数组一样,跟在一个指定初始化项目之后的常规初始化项目为跟在指定成员后的成员提供了初始值。另外,对特定成员的最后一次赋值是它实际获得的值。例如,考虑下列声明:
struct book gift = { .value =
18.90,
.author = "Philionna
pestle",
0.25};
这将把值0.25赋给成员value,因为它在结构声明中紧跟在author成员之后。新的值0.25代替了早先的赋值18.90。
有关designated initializer的进一步信息可以参考c99标准的6.7.8节Ininialization。
标准C89需要初始化语句的元素以固定的顺序出现,和被初始化的数组或结构体中的元素顺序一样。在ISO
C99中,你可以按任何顺序给出这些元素,指明它们对应的数组的下标或结构体的成员名,并且GNU
C也把这作为C89模式下的一个扩展。这个扩展没有在GNU C++中实现。
为了指定一个数组下标,在元素值的前面写上“[index]
=”。比如:
int a[6] = { [4] = 29, [2] = 15 };
相当于:
int a[6] = { 0, 0, 15, 0, 29, 0 };
下标值必须是常量表达式,即使被初始化的数组是自动的。
一个可替代这的语法是在元素值前面写上“.[index]”,没有“=”,但从GCC
2.5开始就不再被使用,但GCC仍然接受。为了把一系列的元素初始化为相同的值,写为“[first ... last] =
value”。这是一个GNU扩展。比如:
int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };
如果其中的值有副作用,这个副作用将只发生一次,而不是范围内的每次初始化一次。
注意,数组的长度是指定的最大值加一。
在结构体的初始化语句中,在元素值的前面用“.fieldname = ”指定要初始化的成员名。例如,给定下面的结构体,
struct point { int x, y; };
和下面的初始化,
struct point p = { .y = yvalue, .x = xvalue };
等价于:
struct point p = { xvalue, yvalue };
另一有相同含义的语法是“.fieldname:”,不过从GCC 2.5开始废除了,就像这里所示:
struct point p = { y: yvalue, x: xvalue };
“[index]”或“.fieldname”就是指示符。在初始化共同体时,你也可以使用一个指示符(或不再使用的冒号语法),来指定共同体的哪个元素应该使用。比如:
union foo { int i; double d; };
union
foo f = { .d = 4 };
将会使用第二个元素把4转换成一个double类型来在共同体存放。相反,把4转换成union
foo类型将会把它作为整数i存入共同体,既然它是一个整数。(参考5.24节向共同体类型转换。)
你可以把这种命名元素的技术和连续元素的普通C初始化结合起来。每个没有指示符的初始化元素应用于数组或结构体中的下一个连续的元素。比如,
int a[6] = { [1] = v1, v2, [4] = v4 };
等价于
int a[6] = { 0, v1, v2, 0, v4, 0 };
当下标是字符或者属于enum类型时,标识数组初始化语句的元素特别有用。例如:
int whitespace[256]
= { [' '] = 1, ['\t'] = 1, ['\h'] = 1,
['\f'] = 1, ['\n'] = 1, ['\r'] = 1 };
你也可以在“=”前面写上一系列的“.fieldname”和“[index]”指示符来指定一个要初始化的嵌套的子对象;这个列表是相对于和最近的花括号对一致的子对象。比如,用上面的struct
point声明:
struct point ptarray[10] = {
[2].y = yv2, [2].x = xv2, [0].x = xv0 };
如果同一个成员被初始化多次,它将从最后一次初始化中取值。如果任何这样的覆盖初始化有副作用,副作用发生与否是非指定的。目前,gcc会舍弃它们并产生一个警告。
Linux C中结构体初始化的更多相关文章
- Linux下C结构体初始化[总结]
1.前言 今天在公司看一同事写的代码,代码中用到了struct,初始化一个struct用的是乱序格式,如下代码所示: typedef struct _data_t { int a; int b; }d ...
- Linux下C结构体初始化
1.前言 今天在公司看一同事写的代码,代码中用到了struct,初始化一个struct用的是乱序格式,如下代码所示: typedef struct _data_t { int a; int b; }d ...
- Linux2.6 内核中结构体初始化(转载)
转自:http://hnniyan123.blog.chinaunix.net/uid-29917301-id-4989879.html 在Linux2.6版本的内核中,我们经常可以看到下面的结构体的 ...
- C语言结构体初始化方法
早上苏凯童鞋问我这个问题来着,写在这里. 我了解到的C中结构体初始化的方法大概有三种. 如这里我定义了一个结构体: typedef struct node { int x, y; }Node; 第一种 ...
- Linux C 结构体初始化三种形式
最近看linux代码时发现了结构体 struct 一种新的初始化方式,各方查找对比后总结如下: 1. 顺序初始化教科书上讲C语言结构体初始化是按照顺序方式来讲的,没有涉及到乱序的方式.顺序初始化str ...
- 关于c语言中结构体的初始化
1.先定义结构体类型后再定义结构体变量: 格式为:struct 结构体名 变量名列表: struct book s1,s2,*ss://注意这种之前要先定义结构体类型后再定义变量: 2.在定义结构体类 ...
- Linux C语言结构体-学习笔记
Linux C语言结构体简介 前面学习了c语言的基本语法特性,本节进行更深入的学习. 预处理程序. 编译指令: 预处理, 宏定义, 建立自己的数据类型:结构体,联合体,动态数据结构 c语言表达式工具 ...
- Linux内核kobject结构体分析
1.前言 Linux内核中有大量的驱动,而这些驱动往往具有类似的结构,根据面向对象的思想,可以将共同的部分提取为父类,而这个父类就是kobject,kobject结构体中包含了大量设备的必须信息,而三 ...
- (一)一个工作任务引起的乱战——c#中结构体与byte[]间相互转换
一个工作任务涉及到c#与c++系统间的udp通信,处理了蛮长时间没有完成任务,但是期间接触到不少小知识点.本人是初接触c#,c++语言没有接触过.可能写的东西都很小儿科,暂且记录下来当工作日记把. 先 ...
随机推荐
- Activiti之 Exclusive Gateway
一.Exclusive Gateway Exclusive Gateway(也称为XOR网关或更多技术基于数据的排他网关)经常用做决定流程的流转方向.当流程到达该网关的时候,所有的流出序列流到按照已定 ...
- 烂泥:mysql修改本地主机连接
本文由秀依林枫提供友情赞助,首发于烂泥行天下. 在mysql数据库安装完毕后,为了能远程连接管理mysql数据库.我们一般是在mysql服务器上通过update命令来更新user表中的host记录的. ...
- PHP生成器Generators
下文的第一个逐行读取文件例子用三种方式实现;普通方法,迭代器和生成器,比较了他们的优缺点,很好,可以引用到自己的代码中 ,支持的php版本(PHP 5 >= 5.5.0) 后面的yield讲解, ...
- centos6.5编译安装lamp开发环境
一.系统以及软件的准备 系统及编译安装包的下载地址:http://pan.baidu.com/s/1jIjqinc 密码:ghc2 说明:由于centos6.5是分卷压缩的,且压缩为三个压缩包,所 ...
- ELF Format 笔记(三)—— Section Types
ilocker:关注 Android 安全(新入行,0基础) QQ: 2597294287 ELF 文件中会包含很多 section,所有的 section 都在 section header tab ...
- web报表工具FineReport常用函数的用法总结(报表函数)
说明:本次总结中,凡是以tableName或viewName作为参数因子的.函数在调用的时候均按照先从私有数据源中查找,然后再从公有数据源中查找的顺序. CLASS CLASS(object):返回o ...
- nodejs模块——fs模块
fs模块用于对系统文件及目录进行读写操作. 一.同步和异步 使用require('fs')载入fs模块,模块中所有方法都有同步和异步两种形式. 异步方法中回调函数的第一个参数总是留给异常参数(exce ...
- Java Web之Filter
Filter被称为过滤器或者拦截器,基本功能就是对调用servler过程的拦截,在servlet进行响应和处理前后实现一些特殊功能.其实,Filter过滤器就是一个实现了javax.servlet.F ...
- Caffe 抽取CNN网络特征 Python
Caffe Python特征抽取 转载请注明出处,楼燚(yì)航的blog,http://www.cnblogs.com/louyihang-loves-baiyan/ Caffe大家一般用到的深度学 ...
- 单调队列优化DP,多重背包
单调队列优化DP:http://www.cnblogs.com/ka200812/archive/2012/07/11/2585950.html 单调队列优化多重背包:http://blog.csdn ...