设为首页 加入收藏

TOP

嵌入式C语言自我修养 02:Linux 内核驱动中的指定初始化(一)
2019-08-27 07:34:22 】 浏览:46
Tags:嵌入式 语言 自我 修养 Linux 内核 驱动 指定 初始

2.1 什么是指定初始化

在标准 C 中,当我们定义并初始化一个数组时,常用方法如下:

1 int a[10] = {0,1,2,3,4,5,6,7,8};


按照这种固定的顺序,我们可以依次给 a[0] 和 a[8] 赋值。因为没有对 a[9] 赋值,所以编译器会将 a[9] 默认设置为0。当数组长度比较小时,使用这种方式初始化比较方便。当数组比较大,而且数组里的非零元素并不连续时,这时候再按照固定顺序初始化就比较麻烦了。

比如,我们定义一个数组 b[100],其中 b[10]、b[30] 需要初始化,如果还按照前面的固定顺序初始化,{}中的初始化数据中间可能要填充大量的0,比较麻烦。

那怎么办呢?C99 标准改进了数组的初始化方式,支持指定任意元素初始化,不再按照固定的顺序初始化。

int b[100] ={ [10] = 1, [30] = 2};


通过数组索引,我们可以直接给指定的数组元素赋值。除此之外,一个结构体变量的初始化,也可以通过指定某个结构体域直接赋值。

因为 GNU C 支持 C99 标准,所以 GCC 编译器也支持这一特性。甚至早期不支持 C99,只支持 C89 的 GCC 编译器版本,这一特性也被当作一个 GCC 编译器的扩展特性来提供给程序员使用。

 

2.2 指定初始化数组元素

在 GNU C 中,通过数组元素索引,我们就可以给某个指定的元素直接赋值。

int b[100] = { [10] = 1, [30] = 2 };


在{ }中,我们通过 [10] 数组元素索引,就可以直接给 a[10] 赋值了。这里有个细节注意一下,就是各个赋值之间用逗号 “,” 隔开,而不是使用分号“;”。

如果我们想给数组中某一个索引范围的数组元素初始化,可以采用下面的方式。

int main(void)
{
   int b[100] = { [10 ... 30] = 1, [50 ... 60] = 2 };
   for(int i = 0; i < 100; i++)
  {
       printf("%d ", a[i]);
       if( i % 10 == 0)
           printf("\n");
  }
   return 0;   
}


在这个程序中,我们使用 [10 ... 30] 表示一个索引范围,相当于给 a[10] 到 a[30] 之间的20个数组元素赋值为1。

GNU C 支持使用 ... 表示范围扩展,这个特性不仅可以使用在数组初始化中,也可以使用在 switch-case 语句中。比如下面的程序:

#include<stdio.h>
int main(void)
{
   int i = 4;
   switch(i)
  {
       case 1:
           printf("1\n");
           break;
       case 2 ... 8:
           printf("%d\n",i);
           break;
       case 9:
           printf("9\n");
           break;
       default:
           printf("default!\n");
           break;
  }
   return 0;
}


在这个程序中,当 case 值为2到8时,都执行相同的 case 分支,可以通过 case 2 ... 8: 的形式来简化代码。这里同样也有一个细节需要注意,就是 ... 和其两端的数据范围2和8之间也要空格,不能写成2...8的形式,否则编译就会通不过。

 

2.3 指定初始化结构体成员变量

跟数组类似,在标准 C 中,结构体变量的初始化也要按照固定的顺序。在 GNU C 中我们也可以通过结构域来初始化指定某个成员。

struct student{
   char name[20];
   int age;
};
?
int main(void)
{
   struct student stu1={ "wit",20 };
   printf("%s:%d\n",stu1.name,stu1.age);
?
   struct student stu2=
  {
      .name = "wanglitao",
      .age  = 28
  };
   printf("%s:%d\n",stu2.name,stu2.age);
?
   return 0;
}


在程序中,我们定义一个结构体类型 student,然后分别定义两个结构体变量 stu1 和 stu2。初始化 stu1 时,我们采用标准 C 的初始化方式,即按照固定顺序直接初始化。初始化 stu2 时,我们采用 GNU C 的初始化方式,通过结构域名 .name 和 .age,我们就可以给结构体变量的某一个指定成员直接赋值。非常方便。

 

2.4 Linux 内核驱动注册

在 Linux 内核驱动中,大量使用 GNU C 的这种指定初始化方式,通过结构体成员来初始化结构体变量。比如在字符驱动程序中,我们经常见到这样的初始化:

static const struct file_operations ab3100_otp_operations = {
.open        = ab3100_otp_open,
.read        = seq_read,
.llseek        = seq_lseek,
.release    = single_release,
};


在驱动程序中,我们经常使用 file_operations 这个结构体变量来注册我们开发的驱动,然后以回调的方式来执行我们驱动实现的相关功能。结构体 file_operations 在 Linux 内核中的定义如下:

struct file_operations {
       struct module *owner;
       loff_t (*llseek) (struct file *, loff_t, int);
       ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
       ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
       ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
       ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
       int (*iterate) (struct file *, struct dir_context *);
       unsigned int (*poll) (struct file *, struct poll_table_struct *);
       long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
       long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
       int (*mmap) (struct file *, struct vm_area_struct *);
       int (*open) (struct inode *, struct file *);
       int (*flush) (struct file *, fl_owner_t id);
       int (*release) (struct inode *, struct file *);
       int (*fsync) (struct file *, loff_t,
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Python-Day5 下一篇对自动变速器的控制器建模

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目