C99 Designated initializers(结构体指定初始化)
在阅读GNU/Linux内核代码时,我们会遇到一种特殊的结构初始化方式,这种方式称为指定初始化(Designated initializers)。Designated initializers, a C99 feature, are supported for aggregate types, including arrays, structures, and unions. A designat
在阅读GNU/Linux内核代码时,我们会遇到一种特殊的结构初始化方式,这种方式称为指定初始化(Designated initializers)。
Designated initializers, a C99 feature, are supported for aggregate types, including arrays, structures, and unions. A designated initializer, or designator, points out a particular element to be initialized. A designator list is a comma-separated list of one or more designators. A designator list followed by an equal sign constitutes a designation.
下面我们看一个例子,Linux-2.6.x/drivers/usb/storage/usb.c中有这样一个结构体初始化
static struct usb_driver usb_storage_driver =
{
.owner = THIS_MODULE,
.name = "usb-storage",
.probe = storage_probe,
.disconnect = storage_disconnect,
.id_table = storage_usb_ids,
};
乍一看,这与我们之前学过的结构体初始化差距甚远。其实这就是前面所说的指定初始化在Linux设备驱动程序中的一个应用,它源自ISO C99标准。以下我摘录了C Primer Plus第五版中相关章节的内容,从而就可以很好的理解2.6版内核采用这种方式的优势就在于由此初始化不必严格按照定义时的顺序。这带来了极大的灵活性,其更大的益处还有待大家在开发中结合自身的应用慢慢体会。
已知一个结构,定义如下
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。
特定的初始化
标准C89需要初始化语句的元素以固定的顺序出现,和被初始化的数组或结构体中的元素顺序一样。
在ISO C99中,你可以按任何顺序给出这些元素,指明它们对应的数组的下标或结构体的成员名,并且GNU C也把这作为C89模式下的一个扩展。这个扩展没有在GNU C++中实现。
为了指定一个数组下标,在元素值的前面写上“[index] =”。比如:
int a[6] = { [4] = 29, [2] = 15 };
相当于:
int a[6] = { 0, 0, 15, 0, 29, 0 };
注意:下标值必须是常量表达式
为了把一系列的元素初始化为相同的值,写为“[first ... last] = value”。这是一个GNU扩展。比如:
int widths[] = { [0 ... 9] = 1, [10 ... 98] = 2, [99] = 3 };
在结构体的初始化语句中,在元素值的前面用“.fieldname = ”指定要初始化的成员名。例如,给定下面的结构体,
struct point { int x, y; };
和下面的初始化,
struct point p = { .y = yvalue, .x = xvalue };
等价于:
struct point p = { xvalue, yvalue };
另一有相同含义的语法是“.fieldname:”,不过从GCC 2.5开始废除了,就像这里所示:
struct point p = { y: yvalue, x: xvalue };
“[index]”或“.fieldname”就是指示符。
在初始化共同体时,你也可以使用一个指示符(或不再使用的冒号语法),来指定共同体的哪个元素应该使用。比如:
union foo { int i; double d; }; union foo f = { .d = 4 };
将会使用第二个元素把4转换成一个double类型来在共同体存放。相反,把4转换成union foo类型将会把它作为整数i存入共同体,既然它是一个整数。
你可以把这种命名元素的技术和连续元素的普通C初始化结合起来。每个没有指示符的初始化元素应用于数组或结构体中的下一个连续的元素。比如,
int a[6] = { [1] = v1, v2, [4] = v4 };
等价于
int a[6] = { 0, v1, v2, 0, v4, 0 };
最后指定初始化可以嵌套:
You can also use designators to represent members of nested structures. For example:
struct a {
struct b {
int c;
int d;
} e;
float f;
} g = {.e.c = 3 };
initializes member c of structure variable e, which is a member of structure variable g, to the value of 3.
更多推荐
所有评论(0)