今天在看串口驱动(四)的时候 有这样一个结构体初始化 我很不理解 如下:

static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = {
14  [0] = {
15   .port = {
16    .lock  = SPIN_LOCK_UNLOCKED,
17    .iotype  = UPIO_MEM,
18    .irq  = IRQ_S3CUART_RX0,
19    .uartclk = 0,
20    .fifosize = 16,
21    .ops  = &s3c24xx_serial_ops,
22    .flags  = UPF_BOOT_AUTOCONF,
23    .line  = 0,//端口索引:0
24   }
25  },
26  [1] = {
27   .port = {
28    .lock  = SPIN_LOCK_UNLOCKED,
29    .iotype  = UPIO_MEM,
30    .irq  = IRQ_S3CUART_RX1,
31    .uartclk = 0,
32    .fifosize = 16,
33    .ops  = &s3c24xx_serial_ops,
34    .flags  = UPF_BOOT_AUTOCONF,
35    .line  = 1, //端口索引:1
36   }
37  },
38 #if NR_PORTS > 2
39
40  [2] = {
41   .port = {
42    .lock  = SPIN_LOCK_UNLOCKED,
43    .iotype  = UPIO_MEM,
44    .irq  = IRQ_S3CUART_RX2,
45    .uartclk = 0,
46    .fifosize = 16,
47    .ops  = &s3c24xx_serial_ops,
48    .flags  = UPF_BOOT_AUTOCONF,
49    .line  = 2, //端口索引:2
50   }
51  }
52 #endif
53 };

为什么会在成员函数前加上小数点呢?  我在网上游荡了好一阵找到了“Felix 的博客”,内容如下:

标记化结构初始化语法

在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 };

 

这个声明采用了标记化结构初始化语法。这种写法是值得采用的,因为它使驱动程序在结构的定义发生变化时更具有可移植性,并且使代码更加紧凑且易读。标记化的初始化方法允许对结构成员进行重新排列。在某些场合下,将频繁被访问的成员放在相同的硬件缓存行上,将大大提高性能。

----LLD3

查到这里 我发现一个关键字 “这个声明采用了标记化结构初始化语法” 我就搜索“标记化结构初始化语法” 内容如下:

这是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");       return0;  }

重点就在于main()函数中对my_op结构体的初始化语句,使用点加变量名进行初始化。用过python的人会马上感觉到这与关键字传参是多么的相似。

那它的好处在哪里呢?我想好处有三。首先,标记传参不用理会参数传递的顺序,正如我上面的例子表示的那样,我是先初始化了read2,然后再初始化了read1,程序员不用记忆参数的顺序;再者,我们可以选择性传参,在传统C语言顺序传参中,如果你只想对第三个变量进行初始化,那么你不得不给第一个,第二个参数进行初始化,而有时候一个变量并没有很合适的默认值,而使用标记初始化法,你可以相当自由地对你有把握的参数进行初始化;还有,扩展性更好,如果你要在该结构体中增加一个字段,传统方式下,为了考虑代码修改量,你最好将新添加的字段放在这个结构体的最后面,否则你将要面对大量且无趣的修改,你可能觉得放在哪里没什么关系,但是我们都习惯了,姓名下面是性别,性别下面是年龄,接着是兴趣爱好,最后是事迹描述,如果年龄放在了最后面,难道不别扭么?!

有人提到,该种语法还有利于提高性能,木有感觉出来,我在这里就不谈这点了。

其实,该种初始化语法并不是什么新技术,新定义,它就是ISO C99的一个标准用法,也就是说99年就有了,再说Linus也不会去赶什么时髦的,据说C Primer Plus第五版中提到了这点,不过,我没有看过该书,遗憾,我是直接投入了面向对象的怀抱。

GCC有扩展标记化结构初始化语法,写法是下面这样的:

struct operators my_op = {read2 : read2, read1 : read1, read3 : read3,};

上面的例程为什么在vc++6.0中编译怎么通不过呢???

在 bluedrum  的空间中有篇 名为《C版本差异--- 结构处理差别》的第3点中讲到:

3、标记化结构初始化语法

在标准C中(C89(结构标准初始化是用{}来实始化,在C99的版本,采用了采用可读性更强的标记化实始化,这在LINUX内核和驱动很为常见。

其中VC++ 6.0只支持C89初始化,GCC支持自己标记化或自己扩展初始化。这种初始化采用 .name = value.这样不需要按顺序排序,方便调整实义,在大结构最大程度防止错位的和调整定义带来不便

struct name_str{
 int data;
 char name[120];
 int num;
};
/* 标记式初始化,注意顺序不同,并可缺省 */
struct name_str str ={
  .num = 100;
  .name = "hxy";
  
};

/* C89 初始化 */

struct name_str str2 =
{
 100,"Andrew Huang",-2
};

/* gcc 扩展初始化 */
struct name_str str3 =
{
  name:"bluedrum";
  data:-1
}
}

个人想编译 以上代码 想下个C99编译器 在百度搜索 C99编译器   解决时间:2009-07-10 21:54 回答是

“VC++   2005支持的是C89  
  而不是C99  
  这点可以在一次对VS2005的负责人的采访中看出来  
  他解释了为什么VS2005支持C89   而不支持C99  
   
  目前完全支持C99标准的编译器还不存在  
  支持部分C99标准的编译器也不多  
  做的最好的是GCC”

查到这里 终于明白这是个怎么回事了

截稿了

原文:标记化结构初始化语法 在结构体成员前加上小数点 如 “.open .write .close ”C99编译器

标记化结构初始化语法 在结构体成员前加上小数点 如 “.open .write .close ”C99编译器 .的更多相关文章

  1. C语言标记化结构初始化语法

    C语言标记化结构初始化语法 (designated initializer),而且还是一个ISO标准. #include <stdio.h> #include <stdlib.h&g ...

  2. 标准C的标记化结构初始化语法

    1 struct file_operations { 2         struct module *owner; 3         loff_t (*llseek) (struct file * ...

  3. C基础--结构体成员初始化方式

    之前在linux内核代码中看到结构体成员成员初始化使用类似于.owner = THIS_MODULE, 不太见过,于是搜了个博客,分享下: 转自:http://www.cnblogs.com/Anke ...

  4. C++结构体成员列表初始化

    C++关于struct和class的区别,可以看上一篇文章:c ++ class和struct[转] 结构体成员列表初始化,来个例子: #include <iostream> #inclu ...

  5. C语言语法教程-结构体

    2018-09-30 结构体中成员变量地址是连续的,结构体用于描述记录. Create a struct //---------------------------- //struct1.c //创建 ...

  6. Delphi XE5教程6:单元的结构和语法

    内容源自Delphi XE5 UPDATE 2官方帮助<Delphi Reference>,本人水平有限,欢迎各位高人修正相关错误! 也欢迎各位加入到Delphi学习资料汉化中来,有兴趣者 ...

  7. 使用XML的五种场合,XML基本规则,XML的术语,结构与语法

    在很多研讨会和培训班上我遇到过许多人,他们还不明白为什么要使用XML也不知道如何 在他们的应用中使用XML.一些来自诸如Gartner公司的报告建议说,商业公司不能再做 局外人了,不能对XML置之不理 ...

  8. FFmpeg源代码简单分析:结构体成员管理系统-AVClass

    ===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...

  9. Delphi XE5教程5:程序的结构和语法

    内容源自Delphi XE5 UPDATE 2官方帮助<Delphi Reference>,本人水平有限,欢迎各位高人修正相关错误! 也欢迎各位加入到Delphi学习资料汉化中来,有兴趣者 ...

随机推荐

  1. c# usercontrol 用户自定义控件无法显示在工具箱的解决办法

    由于最开始x86平台,后来换成anyCPU 重新编译也没有删除x86目录下的dll ,也没重新生成 费x86 下的dll , 导致工具箱无法找到目录下的dll 无法加载自定义控件 右击工具栏中的内容选 ...

  2. kubadm创建k8s v1.10集群

    kubadm创建k8s集群 1:服务器信息以及节点介绍 主机名 ip 备注 k8s-master 192.168.0.104 master etcd keepalived k8s-client1 19 ...

  3. lazarus的动态方法和虚拟方法

    动态方法和虚拟方法在delphi里面分别表示: 动态方法 当需要调用父类.祖先类的被覆盖方法的时候,是查找继承树,当找到,就调用.减少了VMT占用,但调用慢一些. 虚拟方法 和动态方法不同的是,记录了 ...

  4. GCC编译的几个步骤

    参考资料: https://blog.csdn.net/czg13548930186/article/details/78331692 一个C/C++文件要经过预处理(preprocessing).编 ...

  5. 设计师们做UI设计和交互设计、界面设计等一般会去什么网站呢?

    明明可靠颜值吃饭,却偏偏要靠才华立身,UI设计师就是这样一群神奇的物种.面对“大的同时小一点”.“五彩斑斓黑”.“下班之前给我”……这些甲方大大刁钻的需求,设计师每天都在咬牙微笑讨生活.你可以批评我的 ...

  6. Python编程笔记(第二篇)二进制、字符编码、数据类型

    一.二进制 bin() 在python中可以用bin()内置函数获取一个十进制的数的二进制 计算机容量单位 8bit = 1 bytes 字节,最小的存储单位,1bytes缩写为1B 1KB = 10 ...

  7. QueryRunner类的八种结果处理集

    package cn.jy.demo; import java.sql.Connection; import java.sql.SQLException; import java.util.List; ...

  8. easyui下拉框过滤优化

    项目中有个需求:编辑combobox的输入域会自动检索匹配项,当没有任何匹配项时,将combobox重置为初始状态. 处理方式:重写输入域的blur事件,判断当前值是否为加载的数据集的子集,如果不是则 ...

  9. SecureCRT乱码解决

    本文不涉及编码,只说明ssh问题产生的乱码 如果终端中输出以下字符,就会出现乱码 echo -e '\xe' 还有 ctrl+v,ctrl+n也能产生乱码 恢复方法 echo -e '\xf'

  10. RNA-Seq数据去接头(Adapter)

    1.adapter是一段短的序列已知的核酸链,用于链接序列未知的目标测序片段. 2.barcode,也称为index,是一段很短的寡居核酸链,用于在多个样品混合测序时,标记不同的样品. 3.inser ...