我正在阅读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文件系统的函数。
答案 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_operations
在GCC 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 *);
...
};
open
,read
,write
是kernel/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类似。