0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

什么是指定初始化?

汽车电子技术 来源:宅学部落 作者:王利涛 2023-02-17 09:32 次阅读

什么是指定初始化

在标准 C 中,当我们定义并初始化一个数组时,常用方法如下:

int a[10] = {0,1,2,3,4,5,6,7,8};

按照这种固定的顺序,我们可以依次给 a[0] 和 a[8] 赋值。因为没有对 a[9] 赋值,所以编译器会将 a[9] 默认设置为0。当数组长度比较小时,使用这种方式初始化比较方便。当数组比较大,而且数组里的非零元素并不连续时,这时候再按照固定顺序初始化就比较麻烦了。

比如,我们定义一个数组 b[100],其中 b[10]、b[30] 需要初始化,如果还按照前面的固定顺序初始化,{}中的初始化数据中间可能要填充大量的0,比较麻烦。

那怎么办呢?C99 标准改进了数组的初始化方式,支持指定任意元素初始化,不再按照固定的顺序初始化。

int b[100] ={ [10] = 1, [30] = 2};

通过数组索引,我们可以直接给指定的数组元素赋值。除此之外,一个结构体变量的初始化,也可以通过指定某个结构体域直接赋值。

因为 GNU C 支持 C99 标准,所以 GCC 编译器也支持这一特性。甚至早期不支持 C99,只支持 C89 的 GCC 编译器版本,这一特性也被当作一个 GCC 编译器的扩展特性来提供给程序员使用。

指定初始化数组元素

在 GNU C 中,通过数组元素索引,我们就可以给某个指定的元素直接赋值。

int b[100] = { [10] = 1, [30] = 2 };

在{ }中,我们通过 [10] 数组元素索引,就可以直接给 a[10] 赋值了。这里有个细节注意一下,就是各个赋值之间用逗号 “,” 隔开,而不是使用分号“;”。

如果我们想给数组中某一个索引范围的数组元素初始化,可以采用下面的方式。

int main(void)
{
int b[100] = { [10 ... 30] = 1,
    [50 ... 60] = 2 };
for(int i=0; i<100; i++)
 {
   printf("%d  ", a[i]);
   if( i % 10 == 0)   
       printf("\\n");
 }
return0;
}

在这个程序中,我们使用 [10 ... 30] 表示一个索引范围,相当于给 a[10] 到 a[30] 之间的20个数组元素赋值为1。

GNU C 支持使用 ... 表示范围扩展,这个特性不仅可以使用在数组初始化中,也可以使用在 switch-case 语句中。比如下面的程序:

#include
int main(void)
{
 int i = 4;
 switch(i)
 {
 case 1:printf("1\\n");
        break;
 case 2 ... 8:printf("%d\\n",i);
        break;
 case 9:printf("9\\n");
        break;
 default:printf("default!\\n");
        break;
 }
 return 0;
}

在这个程序中,当 case 值为2到8时,都执行相同的 case 分支,可以通过 case 2 ... 8: 的形式来简化代码。这里同样也有一个细节需要注意,就是 ... 和其两端的数据范围2和8之间也要空格,不能写成2...8的形式,否则编译就会通不过。

指定初始化结构体成员变量

跟数组类似,在标准 C 中,结构体变量的初始化也要按照固定的顺序。在 GNU C 中我们也可以通过结构域来初始化指定某个成员。

struct student
{
  char name[20];
  int age;
};
 int main(void)
{
   struct student 
          stu1={ "wit",20 };
   printf("%s:%d\\n", \\
        stu1.name,stu1.age);
   struct student stu2=
    {
        .name = "wanglitao",
        .age  = 28
    };
   printf("%s:%d\\n", \\
       stu2.name,stu2.age);
   return 0;
}

在程序中,我们定义一个结构体类型 student,然后分别定义两个结构体变量 stu1 和 stu2。初始化 stu1 时,我们采用标准 C 的初始化方式,即按照固定顺序直接初始化。初始化 stu2 时,我们采用 GNU C 的初始化方式,通过结构域名 .name 和 .age,我们就可以给结构体变量的某一个指定成员直接赋值。非常方便。

Linux 内核驱动注册

在 Linux 内核驱动中,大量使用 GNU C 的这种指定初始化方式,通过结构体成员来初始化结构体变量。比如在字符驱动程序中,我们经常见到这样的初始化:

static const struct 
file_operations 
ab3100_otp_operations = {
.open = ab3100_otp_open,
.read = seq_read,
.llseek = seq_lseek,
.release= single_release,
};

在驱动程序中,我们经常使用 file_operations 这个结构体变量来注册我们开发的驱动,然后以回调的方式来执行我们驱动实现的相关功能。结构体 file_operations 在 Linux 内核中的定义如下:

struct file_operations
{
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *,char __user *, size_t, loff_t *);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
 };

结构体 file_operations 里面定义了很多结构体成员,而在这个驱动中,我们只初始化了部分成员变量,通过访问结构体的成员来指定初始化,非常方便。

指定初始化的好处

这种指定初始化方式,不仅使用灵活,而且还有一个好处就是:代码易于维护。尤其是在 Linux 内核这种大型项目中,几万个文件,几千万的代码量,当成百上千个文件都使用 file_operations 这个结构体类型来定义变量并初始化时,那么一个很大的问题就来了:如果采用标准 C 那种按照固定顺序赋值,当我们的 file_operations 结构体类型发生改变时,如添加成员、减少成员、调整成员顺序,那么使用该结构体类型定义变量的大量 C 文件都需要重新调整初始化顺序,牵一发而动全身,想想这是多么可怕!

我们通过指定初始化方式,就可以避免这个问题。无论file_operations 结构体类型如何变化,添加成员也好、减少成员也好、调整成员顺序也好,都不会影响其它文件的使用。有了指定初始化,再也不用加班修改代码了,妈妈再也不用担心我们整日加班,不回家吃饭了,多好!

备注

教程是《C语言嵌入式Linux高级编程》第5期:Linux内核中的GNU C语法扩展,文本预览版,如果想系统学习Linux内核中的各种GNU C扩展及使用技巧,可百度搜索:“王利涛”,到51CTO学院或CSDN学院点击相关课程即可开始系统学习。

如果您手头暂时没有 Linux 学习环境,也可以在 Windows 环境下安装 C-Free 学习。教程中的 C 语言示例程序在 C-Free 环境下面也能编译通过。当然在这里,还是建议您使用虚拟机安装一个 Linux 学习环境,一个良好的环境更有利于我们的学习,在安装过程有什么疑惑,可以通过邮件(3284757626@qq.com)联系,也可以加入QQ群(475504428),参与技术讨论。

微信公众号:宅学部落

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 编译器
    +关注

    关注

    1

    文章

    1618

    浏览量

    49043
  • 初始化
    +关注

    关注

    0

    文章

    49

    浏览量

    11831
  • 数组
    +关注

    关注

    1

    文章

    414

    浏览量

    25903
收藏 人收藏

    评论

    相关推荐

    数据库读取时显示指定初始化字符串不符合OLEDB规定

    如题。
    发表于 11-15 12:10

    跪求大神出现,编译出错C2450

    */}//*********************************************************************// 问题找出来了,是HCS12编译器只支持C90,不支持C99,“指定初始化(Designated initialize
    发表于 05-08 13:23

    初始化封装

    和仿真开始运行)初始化封装子系统。有关详细信息,请参阅 执行初始化命令。您可以针对以下情况添加封装初始化代码:指定封装参数的初始值。例如,要
    发表于 08-27 07:17

    指定初始化在配置编程中的应用是什么

    、我们首先会定义一个枚举,将数组的大小和索引都用其表示;2、接着我们定义一个结构体,有很多配置数据子属性都表示出来了;3、最后就是初始化这个结构体数组了,例如经常会用到以下形...
    发表于 12-15 07:29

    Linux内核中的C语言语法扩展

    收集一些感觉比较好的博客链接,方便以后再看Linux 内核中的 C 语言语法扩展Linux 内核驱动中的指定初始化宏构造利器:语句表达式Linux 内核第一宏:container_of零长
    发表于 12-15 06:04

    基于OK6410-A的ARM11开发Linux系统讨论

    初始化方式---指定初始化。因为才谭浩强的书上也没有提到过,看过了一些C语言书也没有提到过。今天一查,原来这个是C99标准,这个目前也是最新的标准,之前我也清楚这件事,但是没意识到这是一个差别。网上
    发表于 06-14 15:53

    请问Xtensa C++编译器的C++17版本是否支持指定初始化器呢?

    我的 ESP-IDF v5.0 应用程序是用 C++ 编写的。在我的主 CMakeList.txt 中,我有以下设置:代码:set(CMAKE_CXX_STANDARD 17)set(CMAKE_CXX_STANDARD_REQUIRED ON)我在 `main.cpp` 中添加了以下语句来检查:代码:std::cout
    发表于 03-01 06:39

    请问Xtensa C++编译器的C++17版本是否支持指定初始化器?

    我的 ESP-IDF v5.0 应用程序是用 C++ 编写的。在我的主 CMakeList.txt 中,我有以下设置:set(CMAKE_CXX_STANDARD 17)set(CMAKE_CXX_STANDARD_REQUIRED ON)我在 `main.cpp` 中添加了以下语句来检查:std::cout
    发表于 04-14 08:55

    RealView编译工具4.0版编译器参考指南

    时,Switch语句中的大小写范围可用。当源语言为C90或非严格C++时,可使用C99风格的指定初始化器。 要在GNU模式下编译,请使用编译器选项--gnu。
    发表于 08-18 06:13

    RDA1846S初始化设置

    RDA1846S初始化设置RDA1846S初始化设置RDA1846S初始化设置
    发表于 01-15 17:08 0次下载

    UCOS_III_配置与初始化

    UCOS_III_配置与初始化
    发表于 12-20 22:53 5次下载

    标签HF I PRO应答器芯片的命令和选项的详细资料概述

    识别设备(RFID)和软件开发的工程师,并且希望将扩展的命令和附加的标签HF I PRO应答器芯片/嵌入到自己的阅读器中。该参考指南应与ISO/IEC 15693标准一起使用,该标准指定初始化应答器和读取器之间通信所需的标准协议、命令和其他参数。
    发表于 08-07 17:00 4次下载
    标签HF I PRO应答器芯片的命令和选项的详细资料概述

    ob<x>jective-C中的变量和数据类型的详细资料详解

    编写初始化时,遵循两个策略:如果你的类包含多个初始化方法,其中一个就应该是指定的(desigrated)初始化方法,并且其他所有初始化方法都
    发表于 10-12 15:38 2次下载

    C语言指定初始化器解析及其应用

    C90 标准要求初始化程序中的元素以固定的顺序出现,与要初始化的数组或结构体中的元素顺序相同。但是在新标准 C99 中,增加了一个新的特...
    发表于 02-07 11:28 2次下载
    C语言<b class='flag-5'>指定</b><b class='flag-5'>初始化</b>器解析及其应用

    C语言使用一维数组注意事项

    如果在定义数值型数组时,指定了数组的长度并对之初始化,凡未被“初始化列表”指定初始化的数组元素,系统会自动把它们
    的头像 发表于 03-09 11:37 1149次阅读