C89,C99:C数组结构体联合体快速初始化
1. 背景
C89标准规定初始化语句的元素以固定顺序出现,该顺序即待初始化数组或结构体元素的定义顺序。
C99标准新增指定初始化(Designated Initializer),即可按照任意顺序对数组某些元素或结构体某些成员进⾏选择性初始化,只需指明它们所对应的数组下标或结构体成员名。GNU C将其作为C89模式的扩展。
借助指定初始化特性,可实现数组或结构体元素的快速初始化。
2. 数组初始化
在数组初始化列表中使⽤“[index常量表达式]=value”形式可对index所指定的某个元素进⾏初始化。如:
int arr[6] = { [0]=5, [1]=6, [3] =10, [4]=11 }; 或
int arr[6] = { [0]=5, 6, [3] =10, 11 }; 或
int arr[6] = { [3] =10, 11, [0]=5, 6 }; (指定顺序可变)
均等效于:int arr[6] = {5, 6, 0, 10, 11, 0};
说明:
1) 若在某个指定初始化项⽬后跟有不⾄⼀个值,如[3]=10,11。则多出的数值⽤于对后续的数组元素进⾏初始化,即数值11⽤来初始化arr[4]。
2) C数组初始化⼀个或多个元素后,未初始化的元素将被⾃动地初始化为0或NULL(针对指针变量)。未经过任何初始化的数组,所有元素的值都是不确定的。
当下标是字符或属于枚举类型时,标识数组初始化语句的元素特别有⽤。如:
int whitespace[256] = {
[''] = 1, ['\t'] = 1, ['\h'] = 1,
['\f'] = 1, ['\n'] = 1, ['\r'] = 1 };
static const char* gMsgName[] = {
[MSG_CREATE] = "Create",
[MSG_DELETE] = "Delete",
[MSG_SET] = "Set",
[MSG_GET] = "Get",
[MSG_GET_ALARMS] = "GetAlarms",
[MSG_SET_TABLE] = "SetTable"}; //枚举值变化时,数组⾃动同步更新
这种初始化⽅式可实现简化的映射表,不过在下标指⽰符跨度较⼤时稍显浪费内存。
GNU C还⽀持”[first … last]=value”(…两侧有空格)的形式,将该范围内的若⼲元素初始化为相同值。如:
int arr[]={ [0 ... 3]=1, [4 ... 5]=2, [6 ... 9] =3}; 或
int arr[]={ [0 ... 3]=1, [4 ... 5]=2, [6 ... 8] =3, [9] =3};
均等效于:int arr[10] = {1, 1, 1, 1, 2, 2, 3, 3, 3, 3};
注意,数组长度为指定的最⼤下标值加1。
这种初始化⽅式⽐memset⾼效且⽤途更⼴,如:
int arr[]={ [0 ... 127]=-1 };
等效于:memset(arr, 0xFF, sizeof(arr));
int arr[]={ [0 ... 127]=1 };
不等效于:memset(arr, 1, sizeof(arr));
3. 结构体初始化
结构的指定初始化语法与数组类似,只不过使⽤点运算符和成员名(⽽不是⽅括号和索引值)标识具体的元素。例如,对于结构体 struct Structure{ int a; int b; };或struct Structure{ int a, b; };
有以下⼏种初始化⽅式:
struct Structure tStct = {
.a = 1,
.b = 2
};
⽤“.fieldname=”指定待初始化成员名(成员初始化顺序可变)
struct Structure tStct = {
a : 1,
b : 2
};
⽤“fieldname:”指定待初始化成员名(成员初始化顺序可变)
GCC 2.5已废除,但仍接受
struct Structure tStct = { 1, 2};
内核结构体多采⽤第⼀种初始化⽅式,如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,
};
该⽅式初始化时不必严格按照定义时的顺序,灵活性很⾼。
【例】定义如下结构体
struct book{
定义数组初始化char title[MAXTITL];
char author[MAXAUTL];
float value;
int mask[128];
};
可按照任意顺序使⽤指定初始化项⽬:
struct book gift = { .value = 25.99,
.author = "James Broadfool",
.title = "Rue for the Toad",
.mask[0 ... 127] = -1};
也可只初始化结构体成员value:
struct book surprise = { .value = 10.99 };
正如数组⼀样,跟在指定初始化项⽬后且没有指⽰符(“[index]”或“fieldname”)的常规初始化项⽬为跟在
指定成员后定义的下个成员提供初始值。此外,若对特定成员初始化多次,则最后⼀次赋值是它实际获得的值。
考虑下列声明:
struct book gift = { .value = 18.90,
.author = "Philionna pestle",
0.25};
将把值0.25赋给成员value,因为它在结构体定义中紧跟在author成员之后。新值0.25覆盖前值18.90。
若覆盖初始化有副作⽤(如类型不兼容),则GNU C可能会产⽣编译警告。
4 联合体初始化
可⽤“.fieldname” (或已废弃的“fieldname:”)指⽰符来指定使⽤联合体的哪个元素,如:
union UnionT { int i; double d; };
union UnionT tUnion = { .d = 4 };
使⽤第⼆个元素将4转换为double类型存⼊联合体。相反,将4转换为union UnionT类型则会把它作为整数i存⼊联合体。
5 结构体数组初始化
可在“=”前写上⼀系列的“[index]”和“.fieldname”指⽰符来指定待初始化的嵌套⼦对象,如:
struct Structure ptStct[10] = {
[2].b = 0x2B, [2].a = 0x2A,
[0].a = 0x0A };
6 GCC扩展结构体赋值
对于上⽂定义的结构体Structure可整体赋值:
struct Structure tStct1, tStct2;
tStct2 = tStct1;
结构体也可作为函数返回值对另⼀个结构体赋值:
struct Structure func1();
struct Structure tStct = func1();
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论