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。

这篇转载大致解决了我们疑惑的问题。其实很简单,绕来绕去的,不就是初始化吗!

但是随后又在c语言扩展中找到了如下的起码是我不知道的事情。

标准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会舍弃它们并产生一个警告。

时间: 2024-10-12 04:34:28

Linux C中结构体初始化的相关文章

Linux下C结构体初始化[总结]

1.前言 今天在公司看一同事写的代码,代码中用到了struct,初始化一个struct用的是乱序格式,如下代码所示: typedef struct _data_t { int a; int b; }data_t; data_t data = { .a = 10, .b = 20, }; 通常初始化一个结构体的方式是按序初始化,形如:data_t data={10,20}.感觉很好奇,如是上网百度一下,发现linux下struct初始化可以采用顺序和乱序两种方式,而乱序又有两种不同的形式. 本文总

Linux下C结构体初始化

原文地址在这里: http://www.cnblogs.com/Anker/p/3545146.html 我 只把里面的主要介绍和代码写到这里了. 顺序初始化 教科书上讲C语言结构体初始化是按照顺序方式来讲的,没有涉及到乱序的方式.顺序初始化struct必须要按照成员的顺序进行,缺一不可,如果结构体比较大,很容易出现错误,而且表现形式不直观,不能一眼看出各个struct各个数据成员的值. 形如; data_t data={10,20} 乱序初始化 乱序初始化是C99标准新加的,比较直观的一种初始

Linux2.6 内核中结构体初始化(转载)

转自:http://hnniyan123.blog.chinaunix.net/uid-29917301-id-4989879.html 在Linux2.6版本的内核中,我们经常可以看到下面的结构体的定义和初始化.这在以前的C语言书中是极少见到的.下面的一个结构体来自到Linux内核中的一部分.在这个结构体中我们可以看到有普通的整型变量,也有函数的指针. struct net_proto_family { int family; int (*create)(struct net *net, st

C语言结构体初始化方法

早上苏凯童鞋问我这个问题来着,写在这里. 我了解到的C中结构体初始化的方法大概有三种. 如这里我定义了一个结构体: typedef struct node { int x, y; }Node; 第一种: Node a = {1, 2}; 第二种: Node b = {x:1, y:2}; 第三种: Node c = { .x = 1, .y = 2 } 当然,上述的初始化方法不是必须每个成员都要初始化,可以指定初始化. 附上一个不错的学习链接:点我

Linux C 结构体初始化三种形式

最近看linux代码时发现了结构体 struct 一种新的初始化方式,各方查找对比后总结如下: 1. 顺序初始化教科书上讲C语言结构体初始化是按照顺序方式来讲的,没有涉及到乱序的方式.顺序初始化struct必须要按照成员的顺序进行,缺一不可,如果结构体比较大,很容易出现错误,而且表现形式不直观,不能一眼看出各个struct各个数据成员的值. 2.乱序初始化乱序初始化是C99标准新加的,比较直观的一种初始化方式.相比顺序初始化而言,乱序初始化就如其名,成员可以不按照顺序初始化,而且可以只初始化部分

OC类中一些细节问题(对象类存储、类中结构体的用法)

一:OC中得方法名 注意:方法名冒号和后面的and方法名冒号  都是方法名 一:对象的存储细节 类加载到代码区(包括类中得属性和方法).对象动态加载到堆内存中.指向对象的指针存放在栈区. 三:定义类常见的错误 定义类的时候,常见的错误 1)类的定义不能嵌套 2)不要漏写 @end 3) 不要忘记写实现类(如果忘记写了,编译不会报错,运行时候才报错) 4)定义成员变量的大括号经常漏写 5) 如果不写@interface 只有 @implementation 这可以,但是会报警告,建议不要这么写 6

黑马程序员--C语言中结构体-我之理解

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- 什么是结构体? “结构”是一种构造类型,它是由若干“成员”组成的.每一个成员可以是一个基本数据类型或者又是一个构造类型. 为什么要有结构类型? 结构体可以把功能相同的数据组织起来,存在一起,用的时候方便,而且在调用函数时,若 传递参数较多

C#中结构体与字节流互相转换

1.定义与C++对应的C#结构体 在c#中的结构体不能定义指针,不能定义字符数组,只能在里面定义字符数组的引用. C++的消息结构体如下: //消息格式 4+16+4+4= 28个字节 struct cs_message{ u32_t cmd_type; char username[16]; u32_t dstID; u32_t srcID; }; C#定义的结构体如下: [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct

C++中结构体和类的区别

在C++中,结构体是一种特殊形态的类. 结构体和类的唯一区别就是:  结构体和类具有不同的默认访问控制属性. 类中,对于未指定访问控制属性的成员,其访问控制属性为私有类型(private) 结构体中,对于未指定任何访问控制属性的成员,其访问控制属性为公有类型(public) C++中,不使用结构体丝毫不会影响程序的表达能力.C++之所以要引入结构体,是为了保持和C程序的兼容性. 但有时仍会在C++中使用结构体,是因为,可以使用结构体将不同类型数据组成整体,方便于保存数据.(若用类来保存,因类中成