结构体初始化

本文详细探讨了C语言中结构体初始化的多种方式,包括常见的内核初始化方法和ISOC99标准下的指定初始化。通过实例解析,展示了指定初始化带来的灵活性和优势,以及如何在实际开发中运用这一特性。

今天同事聊到内核中结构体初始化,

对结构体

struct a {

int b;

int c;

}

有几种初始化方式:

struct a a1 = {
 .b = 1,
 .c = 2
};
或者
struct a a1 = {
 b:1,
 c:2
}
或者
struct a a1 = { 1, 2};

内核喜欢用第一种,使用第一种和第二种时,成员初始化顺序可变。

 

转一篇文章

http://blog.hjenglish.com/bedford/

在阅读GNU/Linux内核代码时,我们会遇到一种特殊的结构初始化方式。该方式是某些C教材(如谭二版、K&R二版)中没有介绍过的。这种方式称为指定初始化(designated initializer)。下面我们看一个例子,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。

摘自: http://blog.youkuaiyun.com/zhsxcn/archive/2008/02/27/2125211.aspx



5.22 特定的初始化

标准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 };
            

下标值必须是常量表达式,即使被初始化的数组是自动的。

一个可替代这的语法是在元素值前面写上“.[index]”,没有“=”,但从GCC 2.5开始就不再被使用,但GCC仍然接受。为了把一系列的元素初始化为相同的值,写为“[first ... last] = value”。这是一个GNU扩展。比如:

 
int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 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存入共同体,既然它是一个整数。(参考5.24节向共同体类型转换。)

你可以把这种命名元素的技术和连续元素的普通C初始化结合起来。每个没有指示符的初始化元素应用于数组或结构体中的下一个连续的元素。比如,

 
int a[6] = { [1] = v1, v2, [4] = v4 };
            

等价于

 
int a[6] = { 0, v1, v2, 0, v4, 0 };
            

当下标是字符或者属于enum类型时,标识数组初始化语句的元素特别有用。例如:

 
int whitespace[256]
            = { [' '] = 1, ['\t'] = 1, ['\h'] = 1,
            ['\f'] = 1, ['\n'] = 1, ['\r'] = 1 };
            

你也可以在“=”前面写上一系列的“.fieldname”和“[index]”指示符来指定一个要初始化的嵌套的子对象;这个列表是相对于和最近的花括号对一致的子对象。比如,用上面的struct point声明:

 
struct point ptarray[10] = { [2].y = yv2, [2].x = xv2, [0].x = xv0 };
            

如果同一个成员被初始化多次,它将从最后一次初始化中取值。如果任何这样的覆盖初始化有副作用,副作用发生与否是非指定的。目前,gcc会舍弃它们并产生一个警告。

摘自:  http://www.kerneltravel.net/newbie/gcc_man.html#5.22


 

10、 结构体的初试化

gcc开始采用ANSI C的struct结构体的初始化形式:

static struct some_structure = {

.field1 = value,

.field2 = value,

..

};

老版本:非标准的初试化形式

static struct some_structure = {

field1: value,

field2: value,

..

};

摘自:  http://hi.baidu.com/hufeifeihu/blog/item/4991b6fb0ea16e136c22eb39.html
在C++中,结构体初始化有多种方式,以下是详细介绍及示例: ### 构造函数初始化 可以在结构体中定义构造函数来进行初始化。构造函数可以是默认构造函数,也可以是带参数的构造函数。 ```cpp #include <iostream> #include <cstring> struct Stu { int nNum; bool bSex; char szName[20]; char szEmail[100]; // 构造函数初始化 Stu() { nNum = 0; bSex = false; memset(szName, 0, sizeof(szName)); memset(szEmail, 0, sizeof(szEmail)); } }; int main() { Stu student; std::cout << student.nNum << std::endl; return 0; } ``` 上述代码中,`Stu`结构体的构造函数将各个成员变量初始化为特定的值。在`main`函数中创建`Stu`类型的对象`student`时,会自动调用构造函数进行初始化 [^1]。 ### 冒号初始化列表 通过冒号初始化列表可以简洁地初始化结构体成员。 ```cpp #include <iostream> struct Entry { int _key; int _value; Entry(int key = 0, int value = 0): _key(key), _value(value) {} }; int main() { Entry a; Entry b(2, 3); std::cout << a._key << " " << a._value << std::endl; std::cout << b._key << " " << b._value << std::endl; return 0; } ``` 在这个例子中,`Entry`结构体使用冒号初始化列表在构造函数中初始化成员变量`_key`和`_value`。在`main`函数中,创建了两个`Entry`对象,一个使用默认值初始化,另一个使用指定的值初始化 [^4]。 ### 花括号初始化(聚合初始化) 使用花括号可以对结构体进行聚合初始化,按顺序为成员变量赋值。 ```cpp #include <iostream> #include <string> struct Date { int year; double month; std::string day; int a[10]; }; int main() { Date date2 = {2022, 7.0, "22", {1}}; std::cout << date2.year << " " << date2.month << " " << date2.day << " " << date2.a[0] << " " << date2.a[1] << std::endl; return 0; } ``` 这里,`Date`结构体使用花括号进行初始化,按顺序为各个成员变量赋值。对于数组,未显式赋值的元素会被初始化为0 [^3]。 ### 利用`memset`初始化 使用`memset`函数可以将结构体的内存区域初始化为特定的值,通常是0。 ```cpp #include <iostream> #include <cstring> struct Stu { int nNum; bool bSex; char szName[20]; char szEmail[100]; // 构造函数初始化 Stu() { memset(this, 0, sizeof(Stu)); } }; int main() { Stu student; std::cout << student.nNum << std::endl; return 0; } ``` 在`Stu`结构体的构造函数中,使用`memset`将整个结构体的内存区域初始化为0 [^5]。 ### 注意事项 不能在结构体声明中初始化结构体成员,因为结构体声明只是创建一个新的数据类型,还不存在这种类型的变量。例如,以下声明是非法的: ```cpp // 非法结构体声明 struct Date { int day = 23, month = 8, year = 1983; }; ``` 这种声明试图在结构体声明时为成员变量赋初值,是不允许的 [^2]。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值