【Struct(结构体)杂谈之六】无既是有---没有成员变量的Struct(结构体)

2023-10-27

没有成员变量的Struct(结构体)

       在开始本篇之前,想问大家一个问题:

       ---0是什么?

       ---呵呵,就是没有呗!

       ---那好,这5块钱拿去,就当抵我上次向你借的500块钱。

       ---什么?这哪和哪啊!这不一样

       ---可是你自己说的, 0就是“没有”。

       ----我说不清,反正不行,你必须还我500.

 

       0是什么?起什么作用呢?为什么500 ≠ 5?

       这节我们来讨论0 的作用。例如,500块钱,它后面0起到了什么作用呢? 500 的0,表示十和个位“没有”。虽说“没有”,但这个0 却不能省略。因为如果省略了0,一件500块的衣服,你只给5块,小心遭到暴打。


那原因是什么呢?

       在按位计数法中,数位具有很重要的意义。即使十位的数“没有”,也不能不写数字。这时就轮到0 出场了,即0 的作用就是占位。换言之,0 占着一个位置以保证数位高于它的数字不会产生错位。

正因为有了表示“没有”的0,数值才能正确地表现出来。可以说在按位计数法中0是不可或缺的。

 

       打住,这和我们讲的struct有什么关系?

       当然有关系了,请问下面这段代码输出的是什么呢?

#include <iostream>

using namespace std;

struct NoMember
{

};

int main(void)
{
	cout<<"The size of the struct NoMem is:"<<endl;
	cout<<sizeof(NoMember)<<endl;

	getchar();
	return 0;
}

是0呢?还是1?2?3?想必大部分人还是说不出来的,那我们先看看输出结果:
一个没有任何变量的Struct居然占了1个字节的空间。

这不科学!


那这是为什么呢?

不急,让子弹先飞一会儿.....


再看下面一段代码:

#include <iostream>

using namespace std;

struct NoMember
{

};

struct NoMember1
{
	int mA[0];
};

int main(void)
{
	//cout<<endl<<"The size of the struct NoMember is: "<<sizeof(NoMember)<<endl;
	cout<<endl<<"The size of the struct NoMember1 is: "<<sizeof(NoMember1)<<endl;

	getchar();
	return 0;
}

一个结构体里面定义了一个空的数组,那这次的输出会是什么呢?
厄, 这还是一个空的结构体,所以输出还是1吧?
好的,你还真蒙对了,请看结果:



但是,如果struct里面还有另外的变量呢?会是什么情况呢?

#include <iostream>

using namespace std;

struct NoMember
{

};

struct NoMember1
{
	int mA[0];
};

struct NoMember2
{
	char mB;
	int mA[0];
};

int main(void)
{
	//cout<<endl<<"The size of the struct NoMember is: "<<sizeof(NoMember)<<endl;
	//cout<<endl<<"The size of the struct NoMember1 is: "<<sizeof(NoMember1)<<endl;
	cout<<endl<<"The size of the struct NoMember2 is: "<<sizeof(NoMember2)<<endl;

	getchar();
	return 0;
}

这一次的输出是什么呢?

char mB占据4个字节,然后int mA[0]占据1个字节,所以结果应该是5吧? 


但是结果是4,为什么呢?


其实结合500 ≠ 5的话也很好理解,虽然结构体包含0个成员变量,但是结构体起到“占位”的作用,“空结构体”变量必须被存储,编译器为其分配一个字节的空间用于占位了。这样一来,不光可以取地址,两个不同的“空结构体”变量又可以得以区分

我们可以输出各个结构体的地址:

#include <iostream>

using namespace std;

struct NoMember
{

};

struct NoMember1
{
	int mA[0];
};

struct NoMember2
{
	char mB;
	int mA[0];
};

int main(void)
{
	NoMember nm0;
	NoMember1 nm1;
	NoMember2 nm2;

	cout<<endl<<"The size of the struct NoMember is: "<<sizeof(NoMember)<<endl;
	cout<<"The address of the struct of NoMember: 0x"<<&nm0<<endl;

	cout<<endl<<"The size of the struct NoMember1 is: "<<sizeof(NoMember1)<<endl;
	cout<<"The address of the struct of NoMember: 0x"<<&nm1.mA<<endl;

	cout<<endl<<"The size of the struct NoMember2 is: "<<sizeof(NoMember2)<<endl;
	cout<<"The address of the struct of NoMember: 0x"<<&nm2.mA<<"\t0x"<<&nm2.mA<<endl;

	getchar();
	return 0;
}

输出结果如下:



注意下面这份简谱,注意到乐谱上也有很多的休止符,在简谱上也是用0来表示,但是它们不是“没有”, 而是表示不发音!


 

       这些0都不能去掉的,因为去掉,节奏肯定乱了。

0与其说是“空”,还不如说是“填空”更恰当。因为它的作用是占位。


结合这个例子,想必大家就理解了, “空结构体” 为什么需要占用一个字节的空间。


       可见,科学和艺术不分家的啊!


对数组比较熟悉的同学可能会问,怎么可以有0元素数组呢?

是的,如果我们在struct 和class之后定义0元素数组,会编译报错,如下代码所示:

#include <iostream>

using namespace std;

struct NoMember
{

};

struct NoMember1
{
	int mA[0];
};

struct NoMember2
{
	char mB;
	int mA[0];
};


struct NoMember3
{
	int arr[0];
};


int arr[0];


int main(void)
{
	NoMember nm0;
	NoMember1 nm1;
	NoMember2 nm2;

	cout<<endl<<"The size of the struct NoMember is: "<<sizeof(NoMember)<<endl;
	cout<<"The address of the struct of NoMember: 0x"<<&nm0<<endl;

	cout<<endl<<"The size of the struct NoMember1 is: "<<sizeof(NoMember1)<<endl;
	cout<<"The address of the struct of NoMember: 0x"<<&nm1.mA<<endl;

	cout<<endl<<"The size of the struct NoMember2 is: "<<sizeof(NoMember2)<<endl;
	cout<<"The address of the struct of NoMember: 0x"<<&nm2.mA<<"\t0x"<<&nm2.mA<<endl;

	getchar();
	return 0;
}


出错信息如下:

1>e:\code\vs2010_prjs\struct\structdeclare\nomems.cpp(28): error C2466: 不能分配常量大小为 0 的数组


而Stuct里面的0元素数组报的是warning,如下所示:

1>e:\code\vs2010_prjs\struct\structdeclare\nomems.cpp(24): warning C4200: 使用了非标准扩展 : 结构/联合中的零大小数组
1>          当 UDT 包含大小为零的数组时,无法生成复制构造函数或副本赋值运算符

那么,问题又来了,这些 struct里面的0元素数组有什么意义呢?


欲知后事如何,请听下回分解......


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Struct(结构体)杂谈之六】无既是有---没有成员变量的Struct(结构体) 的相关文章

  • C/C++语言实现WiFi(socket)数据收发(客户端和服务端)

    目录 客户端 client 服务端 server C C 实现TCP通信 接收WIFI数据 编程环境 VC 6 0 手机端 使用WiFi调试助手 提示 整个过程在局域网中进行 很多编程语言都可以实现socket通信 本博客将通过C C 实现
  • IUnknown—COM和MFC

    转自 http hi baidu com zhangqiuxi blog item 6d9603ad9c8fe5084b36d6a0 html 问题 我用MFC编写COM程序有一段时间了 知道如何使用宏和嵌套类 以及如何在嵌套类中处理IUn
  • 调用拷贝构造函数的几种情况(附面试题)

    1 深拷贝和浅拷贝 拷贝构造函数的使用 有时候需要自己定义拷贝构造函数 以避免浅拷贝问题 在什么情况下需要用户自己定义拷贝构造函数 一般情况下 当类中成员有指针变量 类中有动态内存分配时常常需要用户自己定义拷贝构造函数 在什么情况下系统会调
  • C++ 中的虚函数及虚函数表

    C 中的虚函数及虚函数表 一 虚函数及虚函数表的定义 二 虚函数表指针和虚函数表的创建时机 三 虚函数实现多态的原理 一 虚函数及虚函数表的定义 虚函数 虚函数就是在基类中定义一个未实现的函数名 使用虚函数的核心目的就是通过基类访问派生类定
  • Qt5学习之路(vs2012下创建一个QT应用程序)2013-10-14

    刚开始学习QT在网上找的资料基本都是使用QT Create进行开发的 VS下开发的学习资料感觉很少很难找的到 视频教程也基本没看到过貌似 因为我们研发中心是使用MFC进行开发开发工具是VS2010 使用QT开发的话基本我们不会再使用QT C
  • 编写程序模拟完成动态分区存储管理方式的内存分配和回收。

    usr bin python coding utf 8 class Table object 空闲分区表 0 开始地址 1 长度 freeTable 占用分区表 0 程序名 1 开始地址 2 长度 useTable def init sel
  • c++得到窗口句柄

    include
  • C/C++中浮点数格式学习——以IEEE75432位单精度为例

    这是浮点数的通常表示形式 在IEEE754中 单精度浮点数有如下形式 32位单精度 单精度二进制小数 使用32个比特存储 1 8 23位长 S Exp Fraction 31 30至23偏正值 实际的指数大小 127 22至0位编号 从右边
  • BP学习算法-构建三层神经网络

    引 人工神经网络 Artificial Neural Networks 简写为ANNs 也简称为神经网络 NNs 或称作连接模型 Connection Model 是一种模仿动物神经网络行为特征 进行分布式并行信息处理的算法数学模型 这种网
  • C++中的RTTI

    文章目录 dynamic cast运算符 指针类型的dynamic cast 引用类型的dynamic cast typeid运算符 使用RTTI type info类 参考资料 RTTI Runtime Type Information
  • c语言判断一个数是否为偶数

    include
  • Trace Function Enter, Exit and Leave

    http developer nokia com community wiki Trace Function Enter Exit and Leave
  • mfc窗口创建的create与oncreate

    在view类中 create 是虚函数由框架调用 是用来 生成一个窗口的子窗口 oncreate 消息响应函数 是用来 表示一个窗口正在生成 某个CWnd的Create函数由当前CWnd的Owner调用 而在CWnd Create中 又会调
  • 【C/C++】 - Linux下查找函数头文件 以及 man命令拓展

    背景 比如现在需要找C语言 sleep函数的头文件 使用man来查找 可以先man sleep 可以发现出来的默认是sleep 1 是一个User Commands 明显不是我们需要的 这里提示了 看sleep 3 那我们查看下sleep
  • Open3D(C++)实现建筑物点云立面和平面分割提取

    Open3D C 实现建筑物点云立面和平面分割提取 近年来 点云技术在城市规划 机器人地图构建等领域得到广泛应用 本篇文章将介绍如何利用Open3D C 库实现建筑物点云立面和平面分割提取 准备工作 首先需要编译安装Open3D库 本文使用
  • visual studio 一直显示正在准备解决方案

    首先重启电脑 无法解决的情况下执行以下步骤 Kill Visual Studio Open Visual Studio without loading a solution Disable AnkhSvn as Source Control
  • stat 函数解析

    stat 函数的简单使用 stat 函数是用来获取文件的各种属性的一个linux下的常用API函数 函数原型为int stat const char path struct stat buf stat定义如下 struct stat dev
  • 【数据结构/C++】树和二叉树_二叉链表

    include
  • 【C++】运算符重载

    加号运算符重载 include
  • C/C++编程:令人印象深刻的高级技巧案例

    C C 编程语言在软件开发领域有着悠久的历史 由于其高效 灵活和底层访问能力 至今仍然被广泛应用 本文将介绍一些在C C 编程中令人印象深刻的高级技巧 帮助读者提升编程水平 更加高效地使用这两种强大的编程语言 一 指针运算与内存管理 C C

随机推荐

  • Vim常用命令记录

    Vim常用命令记录 Vim常用命令记录 移动光标 查找 配置vim 分屏 Vim常用命令记录 移动光标 移动到文件头 gg 移动到文件尾 G 移动到行首 移动到行尾 移到第n行 n 上下左右移动光标 k j h l 查找 查找 跳转到匹配的
  • 2023 4月份 华为硬件开发岗位实习生机考回忆

    2023 4月份 华为硬件开发岗位实习生机考回忆 Proscribe 本帖只用作学习之意 若违反任何要求或侵权将立马删除 其中答案也可能错误 实际的工程应用和理论也有所区别 仅收录部分题目和答案等 仅供参考 如果本帖子有帮到你 欢迎给博主点
  • 驱动开发学习目录

    驱动开发学习目录 1 字符设备驱动开发 2 嵌入式Linux led驱动开发实验 3 新字符设备实验 4 设备树 5 linux 块设备驱动开发 6 并发与竞争 6 1原子操作 6 2自旋锁 6 3信号量 6 4互斥体 7 EC20 4G模
  • java中设置date数据的显示格式

    1 一般 默认格式 格式 星期 月份 日期 时 分 秒 时区 年份 Thu Aug 11 15 19 59 CST 2022 2 simpleDateFormat格式化date类 import java text SimpleDateFor
  • 2021-10-24

    拿勋章拿勋章
  • flutter设置appbar高度

    简单的设置appbar高度 Scaffold appBar PreferredSize child AppBar preferredSize Size fromHeight 60 封装成单独的头部Widget 上文链接
  • Azure微软云

    什么是 Azure 虚拟网络 Azure 虚拟网络 VNet 是 Azure 中专用网络的基本构建块 VNet 使多种类型的 Azure 资源 例如 Azure 虚拟机 VM 能够安全地相互通信 Internet 和本地网络 VNet 类似
  • 【工具】自动搜索Research网站的学术会议排名

    转载请注明出处 小锋学长生活大爆炸 xfxuezhang cn Research com是一个可以搜索学术会议网站的影响因子的网站 好用是好用 但有一个缺点 得手动选择类目 有这么多类目 一个个手动选也太累了 所以做了一个自动搜索的小工具
  • 区块链的技术挑战

    2016年年初 中国人民银行举行数字货币研讨会之后 区块链的概念作为数字货币的关键技术进入了公众视 野 也正是进入2016年后 区块链成为年度各大领域讨论的关键性话题 因为 虽然很多人对区块链并不是十分了解 但是该技术对于金融业 医疗行业
  • 使用keil5仿真和逻辑仪分别观察引脚电平变化

    文章目录 用keil5仿真观察 使用SaleaeLogic16进行协议分析 总结心得 参考资料 用keil5仿真观察 打开 l上一篇 完成的keil工程 直接打开仿真示波器运行时会自动停止 并报错某些地址没有写的权限 此时需要在工程下添加一
  • 数据结构----线性表顺序存储的基本操作

    线性表的抽象数据类型定义 ADT LinearList 数据元素 D ai ai D i 1 2 3 n n gt 0 D 为某一数据类型 结构关系 R lt ai a i 1 gt ai a i 1 D i 1 2 3 n 1 基本操作
  • 华为od机试 C++ 【url拼接】

    题目 题目 给定一个URL的前缀和后缀 我们需要将其合并成一个完整的URL 在合并时 请注意以下几点 如果前缀的结尾没有斜线 而后缀的开头也没有斜线 那么在两者之间需要添加一个斜线 如果前缀的结尾和后缀的开头都有斜线 那么需要保留其中的一个
  • uni.app的剪切板

    uni setClipboardData data this title success function res console log success
  • 微信哪个电话能转人工服务器,如何联系微信人工客服?掌握好窍门,只需30秒可接通,亲测有效...

    原标题 如何联系微信人工客服 掌握好窍门 只需30秒可接通 亲测有效 很多人都会使用微信 但是使用过程中难免会遇到问题 比如账号封号 转错账 支付问题等 如果在机器人自动回答中解决不了问题 想找人工客服就是难上加难 有人说微信人工客服是微信
  • 毕业设计-基于卷积神经网络的指针式仪表识别系统

    目录 前言 课题背景和意义 实现技术思路 一 仪表的识别系统 二 实验及结果分析 实现效果图样例 最后 前言 大四是整个大学期间最忙碌的时光 一边要忙着备考或实习为毕业后面临的就业升学做准备 一边要为毕业设计耗费大量精力 近几年各个学校要求
  • vue3+element-plus el-form表单组件二次封装(vue3+ts项目)TForm组件新增继承 Element-plus 组件的事件使用及el-input 去除前后空格

    2023 03 06 TForm组件新增继承 Element plus 组件的事件使用及el input 去除前后空格 type password 除外 一 简介 HTML 一行代码 可实现表单输入框 日期选择 下拉选择 复选框选中等及规则
  • Spark安装的三种方式

    Spark安装的三种方式 通用配置 部署local模式 直接解压即可 不需要配置 部署Standalone模式 部署Yarn模式 通用配置 解压 tar zxf usr local intsall spark 3 1 1 bin hadoo
  • Java中的private关键字

    private关键字用于类中 作用是保护类中的成员变量或者成员方法的数据安全 凡是被private修饰过后的成员变量或成员方法都不能直接被外界调用 需要先在类中进行数值的修饰才可以被外界调用 private的使用 private 数据类型
  • 名词的过去式

    名词作谓语时 可以有过去式 名词 否定形式 名词 例如 昨日 雨 昨天下雨了 昨日 雨 昨天没下雨
  • 【Struct(结构体)杂谈之六】无既是有---没有成员变量的Struct(结构体)

    没有成员变量的Struct 结构体 在开始本篇之前 想问大家一个问题 0是什么 呵呵 就是没有呗 那好 这5块钱拿去 就当抵我上次向你借的500块钱 什么 这哪和哪啊 这不一样 可是你自己说的 0就是 没有 我说不清 反正不行 你必须还我5