我是老温,一名热爱学习的嵌入式工程师,关注我,一起变得更加优秀!
在嵌入式 C 语言的 C89/C90 标准里面,要求程序员在初始化程序中的各个变量元素时,要以固定的顺序进行,并且要与被初始化的数组和结构体的元素顺序相同。
在后来的新标准 C99/C11 里面,新增加了一个灵活且好用的特性:指定初始化器(Designated Initialize),这个新特性可以允许程序员在初始化数组或结构体时,可以指定特定的元素初始值,而不需要按照固定的顺序。
一、应用示例
指定初始化器,一般可以应用于数组、结构体、联合体,等成员变量的初始化,以下举例说明一下。
(1)数组:
对于普通数组在定义时的元素初始化,比如初始化最后一个元素为9527,使用传统的 C89 语法和C99语法,它们两者之间的差异,如以下代码所示。
int arr_1[5] = {0, 0, 0, 0, 9527}; //使用传统的C89语法
int arr_2[5] = {[4] = 9527}; //使用C99特性,指定初始化器
以上的使用方法比较好理解,对于未被使用的元素都初始化为0,在旧的C89语法里面,需要按数组元素的顺序进行初始化,而使用了C99语法的指定初始化器,可以指定具体的元素索引进行初始化。
我们再来看一种比较复杂的使用场景:
#include <stdio.h>
int main(void)
{
int i;
int num[8] = {11, 22, [4] = 55, 66, 77, [1] = 99};
for (i = 0; i < 8; i++)
printf("index = %2d, num = %dn", i, num[i]);
return 0;
}
程序运行后,具体输出如下:
index = 0, num = 11
index = 1, num = 99
index = 2, num = 00
index = 3, num = 00
index = 4, num = 55
index = 5, num = 66
index = 6, num = 77
index = 7, num = 00
从以上的程序运行输出可以看出,使用指定初始化器对数组进行初始化的时候,如果指定的元素后面有更多的值,那么这些值将被用于初始化指定元素后面的元素,num[4]被初始化为55后,num[5] 和 num[6] 会被初始化为 66 和 77。(需要注意定长数组的溢出问题)
再看一下上面的程序,一开始num[1] 被初始化为22,但后面又被重新指定初始化为[1] = 99,前面的初始值22就会被新的指定的初始值99替代。
(2)结构体与联合体
除了数组,C99 特性还为结构体和联合体提供了指定初始化器,在语法上,结构体或联合体在使用指定初始化器的时候,通常使用“点运算符和成员名”来标识特定的元素。
typedef struct student
{
char name[20];
int age;
char school[20];
int class;
}student_t;
student_t stu_1 =
{
.age = 10,
.name = "John",
.school = "lanxiang",
.class = 3,
};
从以上的代码可以看出,学生 John 的年龄是10岁,在lanxiang学校就读三年级。结构体的成员可以按照任意数量任意顺序进行初始化。
与数组类似的是,对成员最后一次赋值才是该成员的实际初始化值,如下代码所示,class的值由最后的 5 取代了前面 3,(因为class成员在school后面)。
student_t stu_1 =
{
.class = 3,
.school = "lanxiang",
5,
};
二、优点和缺点
优点:
1、提高代码可读性:指定初始化器可以直观地看到元素被初始化了特定的值,而不需要按照成员顺序来赋值。
2、减少错误:在初始化大型数组或结构体时,指定初始化器可以减少因顺序错误导致的初始化错误。
3、提高效率:在某些情况下,使用指定初始化器可以减少代码量,提高编码效率。
4、灵活性:可以为数组或结构体中的特定元素赋值,而不必关心其他元素的初始化顺序。
5、易于维护:当需要修改特定元素的初始值时,只需修改对应的初始化表达式,而不需要重新排列整个初始化列表。
缺点:
1、兼容性问题:指定初始化器是C99标准新引入的特性,旧版本的编译器可能无法识别这种初始化方式。
2、易引起混淆:对于不熟悉指定初始化器的程序员来说,当初始化列表很长时,这种初始化方式容易引起混淆。
3、限制性:在使用指定初始化器时,不能跳过未初始化的元素。例如,不能在数组的第0个元素和第2个元素之间直接初始化第1个元素。
4、性能影响:在某些情况下,编译器可能需要额外的工作来处理指定初始化器,这可能会对编译时间或运行时性能产生轻微影响。
三、注意事项
在使用指定初始化器的时候,需要遵循以下注意事项:
1、确保编译器支持:在使用指定初始化器之前,确保你的编译器支持C99或更新的标准。
2、遵循初始化顺序:在使用指定初始化器时,不能跳过未初始化的元素。例如,不能直接初始化数组的第2个元素而忽略第1个元素。
3、注意全局和静态变量:全局和静态变量在程序开始执行前就已经初始化完成,使用指定初始化器可以确保这些变量具有正确的初始值。
4、避免过度使用:指定初始化器虽然提供了灵活性,但过度使用可能会使代码难以理解和维护。应该在适当的情况下使用它,以保持代码的清晰和简洁。
5、注意内存对齐:在使用指定初始化器初始化结构体时,注意内存对齐问题,确保结构体的布局符合预期。