IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C结构体中定义长度为0的数组的意义 -> 正文阅读

[C++知识库]C结构体中定义长度为0的数组的意义

C结构体中定义长度为0的数组的意义

背景

写这篇博客的起因是在B站看到了一个视频,于是突然想起我之前写的一个动态内存分配器中也使用了类似的方法,于是写篇博客记录一下。

在动态内存分配器中定义了如下的一个结构体:

typedef uint64_t sf_header;
typedef sf_header sf_footer;
/*
 * Structure of a block.
 * The first field of this structure is actually the footer of the *previous* block.
 */
typedef struct sf_block {
    sf_footer prev_footer;  // NOTE: This actually belongs to the *previous* block.
    sf_header header;       // This is where the current block really starts.
    union {
        /* A free block contains links to other blocks in a free list. */
        struct {
            struct sf_block *next;
            struct sf_block *prev;
        } links;
        /* An allocated block contains a payload (aligned), starting here. */
        char payload[0];   // Length varies according to block size.
    } body;
} sf_block;

可以看到,在结构体 sf_block 中定义了一个联合体 body,之所以要定义为联合体而不是直接定义为 char payload[0];,是因为该动态内存分配器需要支持显式空闲链表(双向链表)来提升性能。问题是,联合体 body 中为什么要定义一个长度为0的数组呢?

解释

在实际使用中,动态内存分配器中块的大小是未知的,而结构体类型在定义后它的大小就确定了,为了能够使用结构体类型来描述这种大小未知的块,可以在结构体中定义一个长度为0的数组,为了进一步说明,看一个例子。

// 申请大小为1024个字节的动态内存,注意这个大小是指块中的负载大小,而不包括头部和脚部
sf_block* blk = (sf_block*) sbrk(sizeof(sf_footer) + sizeof(sf_header) + 1024);
// 访问这1024个字节
// blk->body.payload[0],访问第一个字节
// blk->body.payload[1],访问第二个字节
// blk->body.payload[2],访问第三个字节
// 负载的首地址为 blk->body.payload 或者 &blk->body

那为什么要使用 char payload[0];,而不是直接在结构体中定义一个 payload 的指针呢?使用 char payload[0];至少有以下三点好处

  1. 省了一个指针的内存占用(在我的例子中由于需要支持显式空闲链表而并没有体现这个好处)
  2. 因为是结构体,内存是分配在一起的而不是分开的,减少cache失效
  3. 分配和释放内存是很消耗性能的操作,如果用指针将需要两次分配两次释放,而这个只需要一次
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-07 11:00:54  更:2022-05-07 11:01:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/21 3:30:30-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码