Linux源代码中带有方法的结构结构

时间:2019-05-25 12:15:24

标签: linux-kernel c

我正在阅读android内核代码,并且正面临这种数据结构,

static const struct file_operations tracing_fops = {
.open       = tracing_open,
.read       = seq_read,
.write      = tracing_write_stub,
.llseek     = tracing_seek,
.release    = tracing_release,
};

有人可以大致解释这种语法吗?等式的右边是函数名称,稍后将&tracing_fops作为参数传递给另一个启动debugfs文件系统的函数。

2 个答案:

答案 0 :(得分:1)

这只是一个结构初始化,使用字段名称仅将值分配给特定字段。您可以看看struct initialization at cppreference,它演示了这些用例(甚至是更高级的情况,例如省略了特定的字段名等)。

Linux内核源代码经常使用由相关操作的功能指针集组成的结构。这些用于提供相同接口的不同实现,类似于在面向对象的语言中使用类继承来完成的实现。例如,在C ++中,将使用虚拟方法来实现相同的想法,并且将函数指针存储在vtable类中(这意味着在C ++中这将是隐式的而不是显式的)。

在C中使用此结构类似于在C ++中使用虚拟方法使用类的对象的方式,因为您可以使用以下方法简单地调用“方法”之一:

int r = fops->open(inode, filp);

实际的代码通常会测试是否设置了struct成员,因为struct初始化会将未明确提及的指针设置为NULL,因此也可以使用这种struct来实现可选操作。

主要区别在于,在C ++中,您对对象本身有一个隐式引用(this),而在C语言中,在需要时必须将其作为附加参数传递。

答案 1 :(得分:1)

分配是使用Compund Literals的示例。根据{{​​3}}:

  

由括号类型名称组成的后缀表达式   后跟括号括起来的初始化程序列表是 compound   文字。它提供了一个未命名的对象,其值由   初始化程序列表。

根据C99 Section #6.5.2.5,在更简单的版本中:

  

复合文字看起来像是用括号括起来的聚合的转换   初始化列表。它的值是在   强制转换,包含在初始化程序中指定的元素。不像   强制转换的结果,复合文字是左值。 ISO C99及更高版本   支持复合文字。作为扩展,GCC支持化合物   C90模式和C ++中也可以使用文字,尽管如下所述,   C ++语义有些不同。

一个简单的例子:

struct foo { int x; int y; };

func() {
    struct foo var = { .x = 2, .y = 3 };
    ...
}

在问题的示例中,struct file_operationsGCC docs: Compound literals中定义,而tracing_fops在Linux源代码树的include/linux/fs.h文件中。

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 *);
...
};

openreadwritekernel/trace/trace.c,它们是指向函数的指针。解引用函数指针后,它可用作常规函数调用。 tracing_fops结构是file_operations类型。使用复合文字将函数指针成员的值分配给同一trace.c文件中的函数。

使用复合文字,我们不必显式指定/分配结构类型中的所有成员,因为其他成员设置为零或null。使用复合文字创建的结构对象可以传递给函数,而无需依赖于成员顺序。双方的功能参数应相同。例如,

的参数
int (*open) (struct inode *, struct file *);

相同
int tracing_open(struct inode *inode, struct file *file);

在面向对象的程序设计中,这个想法与Function Pointers类似。