长度大小为零的数组(柔性数组、可变数组)

2023-10-29

书山有路勤为径,学海无涯苦作舟

前言

柔性数组(Arrays of Length Zero)是GNU/GCC在C/C++标准下扩展而引出的概念,其主要应用于构造可变长结构体中,嵌入式领域中一般被用于解析不定长数据包情境下。


一、什么是柔性数组

长度大小为0的数组

这种定义是GNU/GCC扩展下引出的新特性,C/C++在C99标准下也对其进行了扩展支持,二者定义可能稍有不同。
GNU/GCC下柔性数组定义

typedef struct _array_
{
    char  flag;
    int   state;
    unsigned char length;
    char  data[0];
}array_zero;

有些编译器并不认可这种定义方式,编译会报错提示数组长度必须大于0

error: #94-D: the size of an array must be greater than zero

取而代之需要采用以下定义,定义一个长度未知的数组

typedef struct _array_
{
    char  flag;
    int   state;
    unsigned char length;
    char  data[];
}array_zero;

二、柔性数组应用及优势对比

现有如下场景

串口交互接收不定长数据包

1、定长数组


由于不清楚有效数据长度,故定义一个比较大的length值。程序申请足够的内存空间,用于存放实际有效数据。

#define MAX_LENGTH   256
typedef struct _array_
{
    char  flag;
    int   state;
    unsigned char length;
    char  data[MAX_LENGTH];
}array_zero;

但往往有效数据长度达不到所定义的MAX_LENGTH,往往会造成内存浪费,优点在于操作简单。

2、指针域


将上面定长数组更换为指针,每次使用时动态开辟length大小的空间,那么就可以减小内存空间浪费,只消耗一个指针域的空间。

typedef struct _array_
{
    char  flag;
    int   state;
    unsigned char length;
    char  *data;
}array_zero;

考虑数据对齐,结构大小大于等于(sizeof(int)×4)。内存消耗上虽然占据优势,但是也造成了使用时需要分配两次内存。相对应的,释放也需要两次。

typedef struct _array_
{
    char  flag;
    int   state;
    unsigned char length;
    char  *data;
}array_zero;

int main(void)
{
    char  CURR_LENGTH=12;
    array_zero *array_test=NULL;
    if((array_test=(array_zero *)malloc(sizeof(array_zero))) != NULL)
    {
        array_test->length=CURR_LENGTH;
        if((array_test->data = (char *)malloc(sizeof(char) * CURR_LENGTH)) != NULL)
        {
            memcpy(array_test->data, "Hello World", CURR_LENGTH);
            printf("%d, %s\n", array_test->length, array_test->data);
        }
    }
    free(array_test->data);
    free(array_test);
    array_test=NULL;
}

唯一可能造成的问题是如果构造函数仅返回结构体指针,上层应用中可能只会释放掉结构体开辟内存,而忽略掉数据内存的释放,从而造成内存泄漏。

3、柔性数组

柔性数组从数据结构上来说不占用内存空间,因为数组名仅仅是标识符号,用来指示结构体内该数据成员地址偏移量,实际表示了一个常量地址。
考虑如下结构体所占大小

typedef struct _array_
{
    char  flag;
    int   state;
    unsigned char length;
    char  data[0];
}array_zero;

使用sizeof输出如下结果,可以看出柔性数组并未占据内存。

This array size is 12

实际使用时也需要为其开辟curr_length大小的空间,不同的是只需要进行一次内存操作。

#pragma pack(1)
typedef struct _array_
{
    char  flag;
    int   state;
    unsigned char length;
    char  data[0];
}array_zero;
#pragma pack()

int main(void)
{
    char  CURR_LENGTH=12;
    array_zero *array_test=NULL;
    if((array_test=(array_zero *)malloc(sizeof(array_zero)+sizeof(char)*CURR_LENGTH)) != NULL)
    {
         array_test->length=CURR_LENGTH;
         memcpy(array_test->data, "Hello World", CURR_LENGTH);
         printf("%d, %s\n", array_test->length, array_test->data);
    }
    free(array_test);
    array_test=NULL;
}

总结


  1. 0为数组不占内存空间,指针变量需要占用指针域空间
  2. 柔性数组在申请内存时同结构体内存连续;指针变量申请内存时地址不连续,需要单独申请和释放
    如有错漏,敬请指正!
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

长度大小为零的数组(柔性数组、可变数组) 的相关文章

  • 编译时运算符

    有人可以列出 C 中可用的所有编译时运算符吗 C 中有两个运算符 无论操作数如何 它们的结果始终可以在编译时确定 它们是sizeof 1 and 2 当然 其他运算符的许多特殊用途可以在编译时解决 例如标准中列出的那些整数常量表达式 1 与
  • EF Core Group By 翻译支持条件总和

    听说 EF Core 2 1 将支持翻译小组 我感到非常兴奋 我下载了预览版并开始测试它 但发现我在很多地方仍然没有得到翻译分组 在下面的代码片段中 对 TotalFlagCases 的查询将阻止翻译分组工作 无论如何 我可以重写这个以便我
  • 如何使用 C# 中的参数将用户重定向到 paypal

    如果我有像下面这样的简单表格 我可以用它来将用户重定向到 PayPal 以完成付款
  • 没有强命名的代码签名是否会让您的应用程序容易被滥用?

    尝试了解authenticode代码签名和强命名 我是否正确地认为 如果我对引用一些 dll 非强命名 的 exe 进行代码签名 恶意用户就可以替换我的 DLL 并以看似由我签名但正在运行的方式分发应用程序他们的代码 假设这是真的 那么您似
  • GLKit的GLKMatrix“列专业”如何?

    前提A 当谈论线性存储器中的 列主 矩阵时 列被一个接一个地指定 使得存储器中的前 4 个条目对应于矩阵中的第一列 另一方面 行主 矩阵被理解为依次指定行 以便内存中的前 4 个条目指定矩阵的第一行 A GLKMatrix4看起来像这样 u
  • 按成员序列化

    我已经实现了template
  • 在哪里可以找到列出 SSE 内在函数操作的官方参考资料?

    是否有官方参考列出了 GCC 的 SSE 内部函数的操作 即 头文件中的函数 除了 Intel 的 vol 2 PDF 手册外 还有一个在线内在指南 https www intel com content www us en docs in
  • 为什么当实例化新的游戏对象时,它没有向它们添加标签? [复制]

    这个问题在这里已经有答案了 using System Collections using System Collections Generic using UnityEngine public class Test MonoBehaviou
  • 显示UnityWebRequest的进度

    我正在尝试使用下载 assetbundle统一网络请求 https docs unity3d com ScriptReference Networking UnityWebRequest GetAssetBundle html并显示进度 根
  • 如何设计以 char* 指针作为类成员变量的类?

    首先我想介绍一下我的情况 我写了一些类 将 char 指针作为私有类成员 而且这个项目有 GUI 所以当单击按钮时 某些函数可能会执行多次 这些类是设计的单班在项目中 但是其中的某些函数可以执行多次 然后我发现我的项目存在内存泄漏 所以我想
  • SolrNet连接说明

    为什么 SolrNet 连接的容器保持静态 这是一个非常大的错误 因为当我们在应用程序中向应用程序发送异步请求时 SolrNet 会表现异常 在 SolrNet 中如何避免这个问题 class P static void M string
  • 垃圾收集器是否在单独的进程中运行?

    垃圾收集器是否在单独的进程中启动 例如 如果我们尝试测量某段代码所花费的进程时间 并且在此期间垃圾收集器开始收集 它会在新进程上启动还是在同一进程中启动 它的工作原理如下吗 Code Process 1 gt Garbage Collect
  • 覆盖子类中的字段或属性

    我有一个抽象基类 我想声明一个字段或属性 该字段或属性在从该父类继承的每个类中具有不同的值 我想在基类中定义它 以便我可以在基类方法中引用它 例如覆盖 ToString 来表示 此对象的类型为 property field 我有三种方法可以
  • 链接器错误:已定义

    我尝试在 Microsoft Visual Studio 2012 中编译我的 Visual C 项目 使用 MFC 但出现以下错误 error LNK2005 void cdecl operator new unsigned int 2
  • 对现有视频添加水印

    我正在寻找一种用 C 在视频上加水印的方法 就像在上面写文字一样 图片或文字标签 我该怎么做 谢谢 您可以使用 Nreco 视频转换器 代码看起来像 NReco VideoConverter FFMpegConverter wrap new
  • 如何将带有 IP 地址的连接字符串放入 web.config 文件中?

    我们当前在 web config 文件中使用以下连接字符串 add name DBConnectionString connectionString Data Source ourServer Initial Catalog ourDB P
  • 基于 OpenCV 边缘的物体检测 C++

    我有一个应用程序 我必须检测场景中某些项目的存在 这些项目可以旋转并稍微缩放 更大或更小 我尝试过使用关键点检测器 但它们不够快且不够准确 因此 我决定首先使用 Canny 或更快的边缘检测算法 检测模板和搜索区域中的边缘 然后匹配边缘以查
  • 混合 ExecutionContext.SuppressFlow 和任务时 AsyncLocal.Value 出现意外值

    在应用程序中 由于 AsyncLocal 的错误 意外值 我遇到了奇怪的行为 尽管我抑制了执行上下文的流程 但 AsyncLocal Value 属性有时不会在新生成的任务的执行范围内重置 下面我创建了一个最小的可重现示例来演示该问题 pr
  • 使用.NET技术录制屏幕视频[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 有没有一种方法可以使用 NET 技术来录制屏幕 无论是桌面还是窗口 我的目标是免费的 我喜欢小型 低
  • 对来自流读取器的过滤数据执行小计

    编辑问题未得到解答 我有一个基于 1 个标准的过滤输出 前 3 个数字是 110 210 或 310 给出 3 个不同的组 从流阅读器控制台 问题已编辑 因为第一个答案是我给出的具体示例的字面解决方案 我使用的实际字符串长度为 450 个

随机推荐

  • python+selenium尝试处理滑块验证

    效果如图 处理思路 1 打开滑动验证页面 这个用selenium一步一步走过去 2 将滑动验证码的整个图片保存下来 3 对图片的像素点进行分析 发现拼图处像素特征如下 1 阴影起点处rgb的第一个值为0 2 阴影处的rgb三个值相加大部分小
  • 【机器学习基础 2】matplotlib库

    目录 一 什么是matplotlib库 二 基本用法 1 绘制简单的线图 plot 函数 2 绘制散点图 scatter 函数 3 绘制条形图 bar 函数 4 绘制饼图 pie 函数 三 重要用法 1 设置样式 2 添加标签 3 设置坐标
  • C++动态库使用

    个人博客地址 https cxx001 gitee io 前言 Windows与Linux下面的动态链接库区别 1 文件后缀不同 Linux动态库的后缀是 so 文件 而window则是 dll 文件 2 文件格式不同 a Linux下是E
  • GT911电容触摸屏使用

    注 转载于https blog csdn net qlexcel article details 99696108 一 介绍与硬件连接 GT911 GT928 GT9147都属于GT9系列非单层多点触控芯片 他们支持的触控点数不同 GT92
  • 什么事IPC(Inter-Process Communication,进程间通信)

    进程间通信IPC 也就是Inter Process Communication的缩写 首先我们明白一个进程其实就是一个狭义上的程序 一个服务器也就是一个进程 比如客户端和服务器的连接就是两个进程在通信 只是这两个进程并不在同一台计算机上 它
  • wsl set default version: 请启用虚拟机平台 windows 功能并确保在 bios 中启用虚拟化

    前段时间电脑偶然间恢复了出厂设置 之前安装的docker之类的东西都得重来了 既然要安装docker 肯定得用到WSL 于是就想要先把WSL的版本切换到2 在运行了如下命令后出现了这么个问题 PS C Users me gt wsl set
  • ​广州地区高校福利来啦!6月29日华为云开发者沙龙门票限时免费领取!

    6月29日华为云开发者沙龙广州站开启报名 华为专家现场指导实操演示并有精品图书相送 了解行业趋势进行技术储备 高校教师 学生免费参会 报名地址 https click hm baidu com clk 7a57cac1ed530949ab0
  • 【Redis 6】缓存穿透、缓存雪崩、缓存击穿(附解决方案、代码)

    各位小伙伴们大家好 欢迎来到这个小扎扎的Redis 6专栏 在这个系列专栏中我对B站黑马的Redis教程进行一个总结 鉴于 看到就是学到 学到就是赚到 精神 这波依然是血赚 O Redis知识点速览 缓存穿透 原理以及解决方案 缓存空对象代
  • Redis入门

    1 前言 1 1 什么是Redis Redis是一个基于内存的key value结构数据库 Redis 是互联网技术领域使用最为广泛的存储中间件 它是 Remote Dictionary Service 的首字母缩写 也就是 远程字典服务
  • 断言(Assert)的用法

    一 概念 编写代码时 我们总是会做出一些假设 断言就是用于在代码中捕捉这些假设 可以将断言看作是异常处理的一种高级形式 使用断言可以创建更稳定 品质更好且不易于出错的代码 当需要在一个值为FALSE时中断当前操作的话 可以使用断言 单元测试
  • 二进制间距

    二进制间距 给定一个正整数 n 找到并返回 n 的二进制表示中两个 相邻 1 之间的 最长距离 如果不存在两个相邻的 1 返回 0 如果只有 0 将两个 1 分隔开 可能不存在 0 则认为这两个 1 彼此 相邻 两个 1 之间的距离是它们的
  • MySQL创建S,P,J,SPJ表,以及SQL语句

    MySQL创建S P J SPJ表 CREATE TABLE S SNO char 9 primary key SNAME char 9 STATUS char 9 CITY char 9 CREATE TABLE P PNO char 9
  • Linux休眠,挂起,待机,关机的区别及相关命令

    转 http blog 163 com kukwkukw 126 blog static 97095900201410672425693 体眠是一种更加省电的模式 它将内存中的数据保存于硬盘中 所有设备都停止工作 当再次使用时需按开关机键
  • 一文读懂深度学习框架下的目标检测(附数据集)

    从简单的图像分类到3D位置估算 在机器视觉领域里从来都不乏有趣的问题 其中我们最感兴趣的问题之一就是目标检测 如同其他的机器视觉问题一样 目标检测目前为止还没有公认最好的解决方法 在了解目标检测之前 让我们先快速地了解一下这个领域里普遍存在
  • 整理的最全 python常见面试题(基本必考)① ②③④⑤⑥⑦⑧⑨⑩

    1 大数据的文件读取 利用生成器generator 迭代器进行迭代遍历 for line in file 2 迭代器和生成器的区别 答 1 迭代器是一个更抽象的概念 任何对象 如果它的类有next方法和iter方法返回自己本身 对于stri
  • Vim进阶

    Vim实用技术 第1部分 实用技巧 http www ibm com developerworks cn linux l tip vim1 index html Vim实用技术 第2部分 常用插件 http www ibm com deve
  • 软件测试13个最容易犯的错误

    目录 一 输入框测试 二 搜索功能测试 三 添加 修改功能 四 删除功能 五 上传图片功能测试 六 查询结果列表 七 返回键检查 八 回车键检查 九 刷新键检查 十 直接URL链接检查 盗链问题 十一 并发问题 十二 业务流程测试 十三 界
  • nvme分区选mbr还是guid_Linux 扩容 / 根分区(LVM+非LVM)

    目录 1 概述 2 CentOS7 LVM根分区扩容步骤 3 CentOS7 非LVM根分区扩容步骤 一 背景 概述 MBR Master Boot Record 主引导记录 和GPT GUID Partition Table GUID意为
  • 和泉纱雾

    和泉纱雾 Time Limit 1000 ms Memory Limit 65536 KiB Submit Statistic Problem Description 众所周知 和泉纱雾是著名的埃罗芒阿老师 画画功力首屈一指 今天我们的埃罗
  • 长度大小为零的数组(柔性数组、可变数组)

    书山有路勤为径 学海无涯苦作舟 目录 前言 一 什么是柔性数组 二 柔性数组应用及优势对比 1 定长数组 2 指针域 3 柔性数组 总结 前言 柔性数组 Arrays of Length Zero 是GNU GCC在C C 标准下扩展而引出