嵌入式C语言(四)

简介: 嵌入式C语言(四)

零长度数组

零长度数组、变长数组都是GNU C编译器支持的数组类型。

什么是零长度数组?

首先肯定长度是为0的数组

ANSI C规定定义一个数组长度必须为一个常数,那么就是这个数组的长度在编译的时候就确定了。

int a[10];

但是在C99标准中规定可以定义一个变长的数组。

int len;
int a[len]

这样可以让我们的数组在运行的时候再确定,这是变长。

GUN C编译器支持这样定义

int a[0];

零长度数组不占用内存存储空间。可以用sizeog进行测试哦。

零长度一般很少单独使用,常常作为结构体的一个成员,构成一个变长结构体。

struct buffer{
  int len;
  int a[0];
};

这个buffer的大小是4.

下面来展示一下这个玩意怎么用的诶?

首先的用处在于通过零长度数组去访问结构体的内存,但是还不占内存。

闲话少说,给大爷们上代码。

struct buffer{
  int len;
  int a[0];
};
struct buffer *buf;
buf =  (struct buffer *)malloc(sizeof(struct buffer)+20);
buf->len = 20;
strcpy(buf->a,"hello zhaixue.cc!\n");
puts(buf->a)//打印到屏幕
free(buf);//配套释放内存
return 0;

使用malloc申请一片内存,大小为sizeof(buffer)+20,即24字节。其中4字节用来表示内存的长度20,剩下的20字节空间,可以通过结构体成员a直接访问这片内存。这里不就把一个字符串放进去了。

内核中的零长度数组

前面说了零长度数组在内核中一般以变长结构体的形式出现。现在看看实际内核是怎么用这个的。来看个内核中USB驱动的应用。

网卡驱动中我们都知道有个玩意叫套接字:socket buffer,这个用来传输数据包的

同样在USB驱动中,也有个类似的叫做URB:USB Request Block,即USB请求块,用来传输USB数据包。它的结构体长这个样子:

这个结构体内定义了USB数据包的传输方向传输地址传输大小传输模式等。这些细节我们不深究,只看最后一个成员

struct usb_iso_packet_descriptor iso_fream_desc[0];

这个是干什么的呢?主要用于USB的同步传输。

USB有4种传输模式:中断传输、控制传输、批量传输和同步传输。不同的USB设备对传输速度、传输数据安全性的要求不同,所采用的传输模式也不同。

USB摄像头对视频或图像的传输实时性要求较高,对数据的丢帧不是很在意,丢一帧无所谓,接着往下传就可以了。所以USB摄像头采用的是USB同步传输模式。

USB摄像头一般会支持多种分辨率,从16*16到高清720P多种格式。不同分辨率的视频传输,一帧图像数据的大小是不一样的,对USB传输数据包的大小和个数需求是不一样的。那么USB到底该如何设计,才能在不影响USB其他传输模式的前提下,适配这种不同大小的数据传输需求呢?

当用户设置不同分辨率的视频格式时,USB就使用不同大小和个数的数据包来传输一帧视频数据。通过零长度数组构成的这个变长结构体就可以满足这个要求。USB驱动可以根据一帧图像数据的大小,灵活地申请内存空间,以满足不同大小的数据传输。而且这个零长度数组又不占用结构体的存储空间。当USB使用其他模式传输时,不受任何影响,完全可以当这个零长度数组不存在。

牛吧!!!

不过吧有个想法关于指针的。

为啥不用指针呢?指针指向的内存也可变化啊。

首先说说这个事:数组名在作为函数参数进行参数传递时,就相当于一个指针。那数组名是指针吗?

数组名在作为参数传递时,传递的确实是一个地址,但数组名绝不是指针,两者不是同一个东西。

数组名用来表征一块连续内存空间的地址,而指针是一个变量,编译器要给它单独分配一个内存空间,用来存放它指向的变量的地址。

其实就是数组名是不能变化的,而指针相当于一个盒子,你可以往里面放东西,但是数组名它就个东西。

对于一个指针变量,编译器要为这个指针变量单独分配一个存储空间,然后在这个存储空间上存放另一个变量的地址,我们就说这个指针指向这个变量。

对于数组名,编译器不会再给它分配一个单独的存储空间,它仅仅是一个符号,和函数名一样,用来表示一个地址。

int array1[10] = {1,2,3,4,5,6,7,8};
int array2[0];
int *p = &array1[5]

交叉编译

反汇编

数组名array1仅仅表示这40个连续存储空间的首地址

指针变量p,编译器给它分配了0x2104c这个存储空间

array2的地址为0x21054,在BSS段的后面。array2符号表示的默认地址是一片未使用的内存空间,仅此而已,编译器绝不会单独再给其分配一个存储空间来存储数组名。(bbs段是未初始化的数据,不占用磁盘空间,是在程序执行前由内核初始化完成。)

因此零长度数组不会对结构体定义造成冗余,而且使用起来很方便。

  • 参考资料:《嵌入式C语言自我修养:从芯片、编译器到操作系统》
目录
相关文章
|
22天前
|
编译器 Linux C语言
嵌入式C语言(八)
嵌入式C语言(八)
19 0
|
22天前
|
存储 编译器 C语言
嵌入式C语言(六)
嵌入式C语言(六)
21 0
|
22天前
|
存储 编译器 程序员
嵌入式C语言(七)
嵌入式C语言(七)
17 0
|
22天前
|
编译器 C语言 芯片
嵌入式C语言(九)
嵌入式C语言(九)
17 0
|
22天前
|
缓存 小程序 编译器
嵌入式C语言(十)
嵌入式C语言(十)
24 0
|
1天前
|
安全 算法 开发工具
【C 言专栏】基于 C 语言的嵌入式系统开发
【5月更文挑战第1天】本文探讨了C语言在嵌入式系统开发中的核心作用。嵌入式系统作为专用计算机系统广泛应用于家电、汽车、医疗等领域,具备实时性、低功耗等特点。C语言因其高效性、可移植性和灵活性成为开发首选。文章介绍了开发流程,包括需求分析、硬件选型、软件设计至部署维护,并强调中断处理、内存管理等关键技术。C语言在智能家居、汽车电子和医疗设备等领域的应用实例展示了其广泛影响力。面对硬件限制、实时性要求和安全挑战,开发者需不断优化和适应新技术趋势,以推动嵌入式系统创新发展。
【C 言专栏】基于 C 语言的嵌入式系统开发
|
2天前
|
传感器 算法 C语言
C语言在嵌入式系统开发中的优化策略与代码实现
C语言在嵌入式系统开发中的优化策略与代码实现
13 1
|
22天前
|
存储 编译器 Linux
嵌入式C语言(五)
嵌入式C语言(五)
15 0
|
29天前
|
Linux API C语言
lua 如何在嵌入式Linux中与c语言结合
lua 如何在嵌入式Linux中与c语言结合
9 1
|
算法 Linux Android开发
本CSDN博主将与北京航天航空大学出版社合作出版<嵌入式C语言技术实战开发>一书
本书作者由以下成员合作编写:     杨源鑫,主编,毕业于广州科技贸易职业学院电子应用技术专业,在校期间一并考取了华南理工大学本科数字媒体艺术专业。2015年7月工作至今,任伟易达集团嵌入式系统工程师一职,主要从事单片机,linux,Android底层开发等相关的技术。
2924 0