You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GBA模拟器开发:如何用Union合并位域单比特且保持结构体为2字节

问题解答

你的需求完全可行,问题出在内部嵌套的union被编译器当作独立成员分配了额外空间,导致结构体总大小超出2字节。以下是两种可行的实现方案,既能保留每个字段的明确名称,又能严格保证结构体大小为2字节:

方案一:外层union共享位域

直接通过外层union为共享位的两个字段分别定义位域布局,确保它们复用同一个比特位:

#include <cstdint>

struct OAMAttribute0 {
    union {
        uint16_t raw;
        // 完整属性布局
        struct {
            uint16_t ypos:             8; // 0-255
            uint16_t rotation_scaling: 1; // 0=off, 1=on
            uint16_t _shared_bit:      1; // 占位,对应共享位
            uint16_t mode:             2; // 0=normal, 1=semi-transparent, 2=obj window, 3=prohibited
            uint16_t mosaic:           1; // 0=off, 1=on
            uint16_t colors:           1; // 0=16/16, 1=256/1
            uint16_t shape:            2; // 0=square, 1=horizontal, 2=vertical, 3=prohibited
        } __attribute__((packed));
        // 旋转缩放模式下的字段
        struct {
            uint16_t : 9; // 跳过前9位(ypos+rotation_scaling)
            uint16_t double_size:      1; // 复用第9位
            uint16_t : 6; // 跳过剩余位
        } __attribute__((packed));
        // 普通模式下的字段
        struct {
            uint16_t : 9; // 跳过前9位
            uint16_t obj_disable:      1; // 复用第9位
            uint16_t : 6; // 跳过剩余位
        } __attribute__((packed));
    } __attribute__((packed));
};

static_assert(sizeof(OAMAttribute0) == 2, "OAMAttribute0 must be 2 bytes");

方案二:修正嵌套结构的packed属性位置

如果偏好原始的嵌套结构,只需把__attribute__((packed))移到包含位域的内层结构体上,而非嵌套的union本身:

#include <cstdint>

struct OAMAttribute0 {
    union {
        uint16_t raw;
        struct {
            uint16_t ypos:             8;
            uint16_t rotation_scaling: 1;
            union {
                uint16_t double_size:  1;
                uint16_t obj_disable:  1;
            };
            uint16_t mode:             2;
            uint16_t mosaic:           1;
            uint16_t colors:           1;
            uint16_t shape:            2;
        } __attribute__((packed)); // 内层结构体加packed,确保位域无padding
    };
} __attribute__((packed)); // 外层结构体也加packed,确保整体无额外空间

static_assert(sizeof(OAMAttribute0) == 2, "OAMAttribute0 must be 2 bytes");

关键说明

  • 位域总位数必须严格等于16(8+1+1+2+1+1+2=16),这样编译器才会把整个结构体压缩到2字节。
  • __attribute__((packed))的作用是禁止编译器插入对齐padding,必须作用在包含位域的结构体上,而非内部的union。
  • 不同编译器(如GCC、Clang)对位域的处理可能有细微差异,static_assert是验证结构体大小的关键手段,确保跨编译环境的一致性。

内容的提问来源于stack exchange,提问作者stubbie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 18:43:09