`
mmdev
  • 浏览: 12893818 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

Linux内核代码-结构体初始化

 
阅读更多

Linux内核代码 结构体初始化
2011-01-24 20:40出处:中国IT实验室作者:佚名【我要评论】
[导读]在阅读GNU/Linux内核代码时,我们会遇到一种特殊的结构初始化方式。该方式是某些C教材(如谭二版、K&R二版)中没有介绍过的。

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

分享到:
评论

相关推荐

    sysfs文件接口修改内核模块变量值-fasync源码

    首先是设备驱动程序的代码,在代码中,我们将这段代码是用C语言编写的Linux内核模块,用于控制LED。它包含了几个来自Linux内核的头文件,如linux/types.h、linux/kernel.h和linux/delay.h。代码定义了一个led_struct...

    《精通Linux 设备驱动程序开发》.(Sreekrishnan).pdf

    5.2.1 驱动程序初始化83 5.2.2 打开与释放86 5.2.3 数据交换88 5.2.4 查找92 5.2.5 控制94 5.3 检测数据可用性95 5.3.1 轮询95 5.3.2 fasync98 5.4 和并行端口交互99 5.5 rtc子系统108 5.6 伪...

    精通LINUX设备驱动程序开发

    目 录 第1章 引言 1 1.1 演进 1 1.2 gnu copyleft 2 1.3 kernel.org 2 1.4 邮件列表和论坛 3 1.5 linux发行版 3 1.6 查看源代码 4 1.7 编译内核 7 1.8 可加载的模块 8 1.9 整装待发 9 第2章 内核 11 2.1...

    Android驱动开发权威指南

    13.3.1网络设备初始化 13.3.2网络数据包的收发 第三篇 实践出真知——Android驱动实践篇 第14章Android HAL层的设计 14.1 Android HAL概述 14.2为Android开发虚拟驱动virtualio 14.3 Android集成C程序访问virtualio ...

    C语言的单链表

    内核链表是一种链表,Linux内核中的链表都是用这种形式实现的 1.特性 内核链表是一种双向循环链表,内核链表的节点节点结构中只有指针域 使用内核链表的时候,将内核链表作为一个成员放入到一个结构体中使用 ...

    linux下串口编程.docx

    linux内核的串口通信要点总结与实例代码,包括串口的初始化、参数设置、开启、关闭,以及所涉及到的各类接口函数调用方法、结构体成员变量分析等。

    libusb 源码(win32 & linux USB开发)

     从函数名称可以看出这个函数是用来初始化相关数据的,这个函数大家只要记住必须调用就行了,而且是一开始就要调用的.  usb_find_busses  函数定义: int usb_find_busses(void);  寻找系统上的usb总线,任何usb...

    C语言的双链表

    内核链表是一种链表,Linux内核中的链表都是用这种形式实现的 1.特性 内核链表是一种双向循环链表,内核链表的节点节点结构中只有指针域 使用内核链表的时候,将内核链表作为一个成员放入到一个结构体中使用 ...

    linux系统USB键盘驱动源码+使用说明文档.zip

    #include <linux/init.h>/*linux初始化模块函数定义*/ #include <linux/usb.h> /*USB设备相关函数定义*/ 2. 定义键盘码表数组: /*使用第一套键盘扫描码表:A-1E;B-30;C-2E…*/ static unsigned char usb_kbd_keycode...

    嵌入式系统/ARM技术中的在驱动模块初始化函数中实现设备节点的自动创建

     我们在刚开始写Linux设备驱动程序的时候,很多时候都是利用mknod命令手动创建设备节点,实际上Linux内核为我们提供了一组函数,可以用来在模块加载的时候自动在/dev目录下创建相应设备节点,并在卸载模块时删除该...

    嵌入式系统/ARM技术中的ARM Linux静态映射分析

     内核提供了一个重要的结构体struct machine_desc ,这个结构体在内核移植中起到相当重要的作用,内核通过machine_desc结构体来控制系统体系架构相关部分的初始化。machine_desc结构体的成员包含了体系架构相关部分的...

    Linux下驱动的应用

    .............\12.2.8HCD初始化模块.c .............\3.8.7实现中断处理程序.c .............\4.12chardevxxx设备的驱动程序设计.c .............\4.13.1cdev 结构体.c .............\4.13.3file_operations ...

    unix分析关于UNIX的一些浅析

    s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *pd)函数实际上就是把初始化数据段中的default_i2c_data0结构体复制过来,然后对GPIO进行配置的函数指针进行了初始化。default_i2c_data0结构体如下: static ...

    Linux驱动之LCD实战视频课程

    总结出怎么写一个lcd的驱动程序的步骤1.分配一个fb_info的结构体2.设置fb_info结构体3.向内核注册register_framebuffer4.硬件相关的初始化

    宋劲彬的嵌入式C语言一站式编程

    1.1. 初始化字符串 1.2. 取字符串的长度 1.3. 拷贝字符串 1.4. 连接字符串 1.5. 比较字符串 1.6. 搜索字符串 1.7. 分割字符串 2. 标准I/O库函数 2.1. 文件的基本概念 2.2. fopen/fclose 2.3. stdin/stdout/stderr ...

    获取USB摄像头的1080p的JPEG格式的图片20180608_1806.7z

    // [日期:2011-03-06] 来源:Linux社区 作者:aokikyon [字体:大 中 小] // // #加了点注释 // // #Rockie Cheng // printf #include #include // memset #include #include #include <getopt.h> #...

Global site tag (gtag.js) - Google Analytics