Linux内核r8169驱动struct pci_driver结构体初始化语法相关问题
#define KBUILD_MODNAME "foo" static struct pci_driver rtl8169_pci_driver = { .name = KBUILD_MODNAME, .id_table = rtl8169_pci_tbl, .probe = rtl_init_one, .remove = rtl_remove_one, .shutdown = rtl_shutdown, .driver.pm = pm_ptr(&rtl8169_pm_ops), };
问题解答
1. 带.前缀的成员赋值语法的正式名称,为什么不需要指定成员数据类型
- 正式名称是指定初始化器(Designated Initializer),是C99标准新增的语法特性,专门用于结构体、联合体、数组的初始化场景,可以显式指定要赋值的成员名,不需要严格按照结构体定义的成员顺序赋值。
- 不需要指定类型是因为
struct pci_driver的类型定义已经明确了每个成员的类型,编译器会根据你写的成员名自动匹配对应的类型,做类型校验和赋值操作,不需要用户重复声明类型。
2. name成员是否在其他位置预先定义
是的,name是struct pci_driver结构体的内置成员,该结构体是Linux内核PCI子系统预设的标准驱动框架结构体,定义在内核源码的include/linux/pci.h头文件中,所有PCI设备驱动都需要实例化这个结构体来完成驱动注册。
3. static struct修饰的作用
注意这里的static是修饰结构体变量rtl8169_pci_driver,不是修饰结构体类型本身,作用有两个:
- 限制该变量的作用域仅在当前源文件(r8169_main.c)内可见,其他内核源文件无法直接引用这个变量,避免全局命名冲突。
- 该变量的存储位置在静态存储区,不会随函数栈回收而销毁,符合驱动结构体需要在内核运行生命周期内长期存在的要求。
4. 为什么可以在结构体声明的同时直接为成员赋值
这是C语言原生支持的变量初始化规则:不管是基础数据类型变量,还是复合类型(结构体、联合体、数组)变量,都支持在声明变量的同时完成初始化操作,不需要拆分成分开的声明、赋值两步。这种写法不仅代码更简洁,也可以避免未初始化的结构体变量被误用。
5. 这类结构体是否支持创建对应的数组
完全支持,C语言允许创建任意结构体类型的数组,同时也可以结合指定初始化器给数组的指定下标元素的指定成员赋值,示例写法如下:
static struct pci_driver drv_list[] = { [0] = { .name = "r8169_dev1", .id_table = rtl8169_pci_tbl_1, .probe = rtl_init_one }, [1] = { .name = "r8169_dev2", .id_table = rtl8169_pci_tbl_2, .probe = rtl_init_one_variant } };
这种用法在内核源码中非常常见,比如多设备支持的驱动列表、设备ID匹配表等场景都会用到。
内容的提问来源于stack exchange,提问作者user786
相关产品推荐
相关产品推荐

