结构体与联合体成员的正确声明语法及相关疑问
结构体与联合体成员的正确声明规则
问题场景
从索尼PlayStation的.SYM符号文件生成头文件后,用Visual Studio Code检测语法时出现错误:
tag kind of union is incompatible with declaration of class "PacketData"
错误示例代码:
struct PacketData { short Data[2]; unsigned long Control; }; struct Packet { unsigned char CheckSum; char Action; short Padw; union PacketData Data; // 此处报错:PacketData已被声明为struct类型,不能当作union标签使用 };
移除PacketData前的union关键字即可解决问题。
以下是DUMPSYM.EXE输出的相关符号信息:
结构体Packet的符号输出
02cc47: $00000000 94 Def class STRTAG type STRUCT size 8 name Packet 02cc5b: $00000000 94 Def class MOS type UCHAR size 0 name CheckSum 02cc71: $00000001 94 Def class MOS type CHAR size 0 name Action 02cc85: $00000002 94 Def class MOS type SHORT size 0 name Padw 02cc97: $00000004 96 Def2 class MOS type UNION size 4 dims 0 tag PacketData name Data 02ccb6: $00000008 96 Def2 class EOS type NULL size 8 dims 0 tag Packet name .eos
联合体PacketData的符号输出
02cbe2: $00000000 94 Def class UNTAG type UNION size 4 name PacketData 02cbfa: $00000000 96 Def2 class MOU type ARY SHORT size 4 dims 1 2 tag name Data 02cc13: $00000000 94 Def class MOU type ULONG size 0 name Control 02cc28: $00000004 96 Def2 class EOS type NULL size 4 dims 0 tag PacketData name .eos
同时存在疑问:为何结构体成员可以选择性添加struct前缀?比如以下代码两种写法都合法:
struct Sprite { unsigned char X; unsigned char Y; unsigned short Page; unsigned char SWidth; unsigned char SHeight; unsigned short Clut; }; struct SpriteData { struct Sprite *Sprites; // 带struct前缀 struct Sprite *EndSprites; unsigned long Data; };
或去掉struct前缀直接写Sprite *Sprites;。
核心规则说明
错误根源解析
你遇到的报错本质是类型标签冲突:在C中,struct PacketData已经将PacketData注册为一个struct类类型,后续再用union PacketData试图将其当作union标签使用,违反了C的类型命名规则——同一个标识符不能同时作为不同类型(struct/union/enum)的标签。去掉union关键字后,直接使用已定义的PacketData类型,就符合语法要求了。
结构体前缀的可选性原因
这取决于你使用的是C还是C++语言:
- C语言:结构体标签不属于全局类型命名空间,必须用
struct 标签名来指代对应的类型。如果想省略struct前缀,需要通过typedef将标签名映射为类型名:typedef struct Sprite Sprite; // 之后即可直接用Sprite代替struct Sprite struct SpriteData { Sprite *Sprites; }; - C++语言:struct(以及union、enum)的标签会直接加入全局类型命名空间,因此
struct Sprite和Sprite是完全等价的类型名,两种写法都合法,可以任选其一。
正确声明方式总结
结构体成员声明
- C语言环境:
- 方式一:始终保留
struct前缀struct SpriteData { struct Sprite *Sprites; struct Sprite *EndSprites; }; - 方式二:用
typedef简化类型名typedef struct Sprite Sprite; struct SpriteData { Sprite *Sprites; Sprite *EndSprites; };
- 方式一:始终保留
- C++语言环境:两种写法均合法,根据习惯选择即可
struct SpriteData { struct Sprite *Sprites; // 合法 Sprite *EndSprites; // 合法 };
联合体成员声明
规则与结构体一致,但需注意标签名不能跨类型重复使用:
- 先定义联合体类型:
union PacketData { short Data[2]; unsigned long Control; }; - 声明成员时:
- C++环境:直接使用标签名
struct Packet { // ... PacketData Data; }; - C语言环境:要么带
union前缀,要么用typedef简化// 写法一:带union前缀 struct Packet { // ... union PacketData Data; }; // 写法二:typedef简化 typedef union PacketData PacketData; struct Packet { // ... PacketData Data; };
- C++环境:直接使用标签名
内容的提问来源于stack exchange,提问作者aybe
相关产品推荐
相关产品推荐

