结构体包含大小为零的数组时情况分析

本文探讨了C/C++中零大小数组在结构体中的使用限制。解释了为什么零大小数组必须位于结构体的末尾,并且不占用结构体的空间。同时介绍了编译器对于此类结构体的警告和错误信息。

在分析某代码时,发现某结构体定义为

typedef struct _BUSENUM_PLUGIN_HARDWARE
{
	//
	// sizeof (struct _BUSENUM_HARDWARE)
	//
	__in ULONG Size;        

	//
	// Unique serial number of the device to be enumerated.
	// Enumeration will be failed if another device on the 
	// bus has the same serail number.
	//

	__in ULONG SerialNo;


	//
	// An array of (zero terminated wide character strings). The array itself
	//  also null terminated (ie, MULTI_SZ)
	//

	__in  WCHAR   HardwareIDs[]; 

} BUSENUM_PLUGIN_HARDWARE, *PBUSENUM_PLUGIN_HARDWARE;

最开始以为sizeof(BUSENUM_PLUGIN_HARDWARE)等于12,因为我认为WCHAR HardwareID[]等效于WCHAR HardwareID[1]。但具体测试时发现其结构体大小为8,即结构体不包含最后一个成员,并且应用层编译器会有警告:

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

如果在结构体附加一个成员(需要内存空间或者另外一个大小为零的数组)

typedef struct _BUSENUM_PLUGIN_HARDWARE
{
	//
	// sizeof (struct _BUSENUM_HARDWARE)
	//
	__in ULONG Size;        

	//
	// Unique serial number of the device to be enumerated.
	// Enumeration will be failed if another device on the 
	// bus has the same serail number.
	//

	__in ULONG SerialNo;


	//
	// An array of (zero terminated wide character strings). The array itself
	//  also null terminated (ie, MULTI_SZ)
	//

	__in  WCHAR   HardwareIDs[]; 

	//__in WCHAR  Name[]; 
	__in ULONG		ulRear;

} BUSENUM_PLUGIN_HARDWARE, *PBUSENUM_PLUGIN_HARDWARE;

编译器会报告错误:

error C2229: struct“_BUSENUM_PLUGIN_HARDWARE”有非法的大小为零的数组
所以,一个结构体可以包含一个大小为0的数组,但是必须处于结构体末尾,并且其不占用结构体内存空间。

<think> 首先,用户的问题是:“声明结构体变量和声明结构体数组有什么不同”,意思是“在声明结构体变量和声明结构体数组有什么不同”。 我需要用中文回答这个问题,因为用户指定了“请使用中文回答问题”。 回答完问题后,我必须在末尾提出3-5个 §§相关问题§§。第一行必须是完整的“§§相关问题§§”,禁止换行分散。相关问题必须基于用户的问题和我的回答。 回想规则: - 回答完问题后,输出“§§相关问题§§”作为第一行。 - 然后列出3-5个相关的问题。 - 所有内容符合规则,否则无效。 用户的问题是关于C语言或类似编程语言中的结构体声明。关键点: - 声明结构体变量:例如,`struct MyStruct var;`,这声明了一个名为`var`的结构体变量。 - 声明结构体数组:例如,`struct MyStruct arr[10];`,这声明了一个包含10个元素的数组,每个元素是`struct MyStruct`类型。 主要区别: 1. **语法**:变量声明直接指定变量名;数组声明需要添加方括号和大小(如`[10]`)。 2. **内存分配**:变量分配单个结构体的内存;数组分配连续的内存块用于多个结构体。 3. **访问方式**:变量通过名称直接访问;数组通过索引访问(如`arr[0]`)。 4. **用法**:变量用于存储单个实例;数组用于存储多个同类型实例。 在我的回答中,我需要简洁明了地解释这些区别,使用中文。 现在,回答结构: - 先回答用户的问题。 - 然后,以“§§相关问题§§”开头。 - 列出3-5个相关问题: - 基于用户的问题(结构体声明)。 - 也可能基于我的回答(如内存、访问方式等)。 - 例如: 1. 结构体变量和数组在内存布局上有什么区别? 2. 如何动态分配结构体数组? 3. 结构体数组成员访问需要注意什么? 4. 等。 确保相关问题数量在3-5个。 最后,输出格式: - 回答部分。 - 然后“§§相关问题§§” - 接着问题列表,如“1. ... 2. ... 3. ...”等。 现在,草拟回答: 回答: 在编程中,声明结构体变量和声明结构体数组的主要区别在于: - **声明结构体变量**:例如在C语言中,`struct Person p;` 声明了一个名为 `p` 的单个结构体变量。 - **声明结构体数组**:例如 `struct Person employees[5];` 声明了一个包含5个元素的数组,每个元素是 `struct Person` 类型。 区别包括: 1. **语法**:数组声明需要在变量名后添加方括号和大小指定符。 2. **内存分配**:变量分配单个结构体大小的内存;数组分配连续的内存块,大小为元素数量乘以结构体大小。 3. **访问**:变量可直接访问(如 `p.age`);数组通过索引访问(如 `employees[0].age`)。 4. **初始化**:初始化方式不同,数组可以使用初始化列表。 5. **用途**:变量用于单个实体;数组用于集合。 然后,相关问题: §§相关问题§§ 1. 如何初始化结构体数组? 2. 结构体数组在内存中是连续存储的吗? 3. 结构体变量可以作为函数参数传递吗? 4. 结构体数组大小可以在运行动态指定吗? 5. 结构体数组和指针数组有什么区别? 相关问题需要基于用户的问题和我的回答。用户的问题是“声明有什么不同”,所以我应该聚焦在声明相关的方面。 优化相关问题: 1. 在C语言中,声明结构体数组是否可以省略大小? 2. 结构体变量和数组在函数内部声明,作用域有什么不同? 3. 如何动态声明结构体数组? 4. 结构体数组的元素可以是不同的类型吗?(如果结构体是同质的,则不行,但可以问) 5. 结构体声明和数组声明在编译如何处理? 保持相关性和数量3-5个。 最终输出: - 回答部分(中文)。 - §§相关问题§§ - 1. ... 2. ... 3. ...(数字列表)。 </think> 在编程中,声明结构体变量和声明结构体数组的主要区别如下: 1. **语法差异**: - **结构体变量**:直接声明单个变量,语法如 `struct MyStruct var;`,其中 `var` 是变量名。 - **结构体数组**:需添加方括号指定元素数量,语法如 `struct MyStruct arr[5];`,表示一个包含 5 个元素的数组。 2. **内存分配**: - **结构体变量**:分配单个结构体的内存空间(例如,一个 `MyStruct` 的大小)。 - **结构体数组**:分配连续的内存块,大小为元素数量乘以单个结构体大小(例如,5 个 `MyStruct` 的连续内存)。 3. **访问方式**: - **结构体变量**:通过变量名直接访问成员,如 `var.member`。 - **结构体数组**:通过索引访问元素,然后访问成员,如 `arr[0].member`。 4. **用途场景**: - **结构体变量**:适用于存储单条数据(如一个用户信息)。 - **结构体数组**:适用于存储多条同类型数据(如一组用户列表)。 5. **初始化和操作**: - **结构体变量**:初始化简单,如 `struct MyStruct var = {value1, value2};`。 - **结构体数组**:初始化需使用列表,如 `struct MyStruct arr[2] = {{v1,v2}, {v3,v4}}`;操作需遍历索引。 简单示例(C语言): ```c // 声明结构体类型 struct Point { int x; int y; }; // 声明结构体变量 struct Point p1; // 单个点 // 声明结构体数组 struct Point points[3]; // 包含3个点的数组 ``` 这些区别在内存管理、代码效率和可读性上都有重要影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值