在Linux2.6内核中对结构体的定义形式发生了变化,不再支持原来的定义形式。
1 static struct tty_operations uart_ops =
2 {
3 .open = uart_open,//串口打开
4 .close = uart_close,//串口关闭
5 .write = uart_write,//串口发送
6 .put_char = uart_put_char,//...
7 .flush_chars = uart_flush_chars,
8 .write_room = uart_write_room,
9 .chars_in_buffer= uart_chars_in_buffer,
10 .flush_buffer = uart_flush_buffer,
11 .ioctl = uart_ioctl,
12 .throttle = uart_throttle,
13 .unthrottle = uart_unthrottle,
14 .send_xchar = uart_send_xchar,
15 .set_termios = uart_set_termios,
16 .stop = uart_stop,
17 .start = uart_start,
18 .hangup = uart_hangup,
19 .break_ctl = uart_break_ctl,
20 .wait_until_sent= uart_wait_until_sent,
21 #ifdef CONFIG_PROC_FS
22 .read_proc = uart_read_proc, //proc入口读函数
23 #endif
24 .tiocmget = uart_tiocmget,
25 .tiocmset = uart_tiocmset,
26 };
这个声明采用了标记化结构初始化语法。这种写法是值得采用的,因为它使驱动程序在结构的定义发生变化时更具有可移植性,并且使代码更加紧凑且易读。标记化的初始化方法允许对结构成员进行重新排列。在某些场合下,将频繁被访问的成员放在相同的硬件缓存行上,将大大提高性能。
这是ISO C99的用法
C Primer Plus第五版中相关章节:
已知一个结构,定义如下
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语言标记化结构初始化语法
以前在看Linux代码时,就对它的结构体初始化写法感到奇怪,所有的初始化代码都写清了变量名,并且变量名前面还有一个诡异的点。最近学习Linux设备驱动,又遇到了,就查了一下,发现自己的知识果然纰漏不少,此种初始化写法并不是什么特殊的代码风格,而是所谓的C语言标记化结构初始化语法(designated initializer),而且还是一个ISO标准。在此我就小小科普一下。
代码举例如下:
#include <stdio.h>
#include <stdlib.h>
struct operators
{
void (*read1)(char *);
void (*read2)(char *);
void (*read3)(char *);
int n;
};
void read1(char *data)
{
printf("read1: %s\n",data);
}
void read2(char *data)
{
printf("read2: %s\n",data);
}
void read3(char *data)
{
printf("read3: %s\n",data);
}
int main()
{ //传统的初始化方法
//struct operators my_op = {read1, read2, read3, 100}; //所谓的标记化结构初始化语法
struct operators my_op = {.read2 = read2,
.read1 = read1,
.read3 = read3,
.n = 100};
my_op.read1("wangyang");
my_op.read2("wangyang");
my_op.read3("wangyang");
return 0;
}重点就在于main()函数中对my_op结构体的初始化语句,使用点加变量名进行初始化。用过python的人会马上感觉到这与关键字传参是多么的相似。
那它的好处在哪里呢?我想好处有三。首先,标记传参不用理会参数传递的顺序,正如我上面的例子表示的那样,我是先初始化了read2,然后再初始化了read1,程序员不用记忆参数的顺序;再者,我们可以选择性传参,在传统C语言顺序传参中,如果你只想对第三个变量进行初始化,那么你不得不给第一个,第二个参数进行初始化,而有时候一个变量并没有很合适的默认值,而使用标记初始化法,你可以相当自由地对你有把握的参数进行初始化;还有,扩展性更好,如果你要在该结构体中增加一个字段,传统方式下,为了考虑代码修改量,你最好将新添加的字段放在这个结构体的最后面,否则你将要面对大量且无趣的修改,你可能觉得放在哪里没什么关系,但是我们都习惯了,姓名下面是性别,性别下面是年龄,接着是兴趣爱好,最后是事迹描述,如果年龄放在了最后面,难道不别扭么?!
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ranruoyu1003/archive/2010/12/29/6104518.aspx
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ranruoyu1003/archive/2010/12/29/6104518.aspx