C++中如何指定类的大小?怎么实现刚好占3字节的自定义浮点数类?
问题原因
你定义的位域总长度是 1+6+17=24 位,刚好等于3字节的总位数,之所以得到4字节大小,是因为C++中位域的默认对齐规则:你使用unsigned int作为位域的基础类型,大多数平台上unsigned int的大小是4字节,编译器默认会将整个位域结构对齐到基础类型的大小,所以最终类的大小被填充到了4字节。
解决方案
方案1:使用编译指令强制对齐(实现简单)
绝大多数主流编译器(GCC、Clang、MSVC)都支持#pragma pack编译指令,可以临时修改结构体/类的对齐规则,设置为1字节对齐即可避免多余填充:
#pragma pack(push, 1) // 保存原有对齐设置,强制设置为1字节对齐 class FloatingPointNumber { private: unsigned int sign : 1; unsigned int exponent : 6; unsigned int mantissa : 17; }; #pragma pack(pop) // 恢复原有对齐设置,避免影响后续代码的对齐规则
该方案修改成本极低,修改后类的大小就是3字节。需要注意的是,C++标准中位域的内存布局、位顺序是编译器实现定义的,跨编译器兼容性有限,如果你的代码需要跨不同编译器运行,建议选择方案2。
方案2:手动操作字节数组(可控性高、兼容性好)
如果需要完全控制内存布局,避免不同编译器位域实现差异带来的问题,可以直接定义3字节的存储数组,自己实现对应位段的读写逻辑:
#include <cstdint> class FloatingPointNumber { private: // 固定3字节存储,布局可自定义,示例布局如下: // data[0] bit7: 符号位 | bit6~bit1: 指数位 | bit0: 尾数最高位 // data[1] 全部8位、data[2]全部8位:尾数低16位 uint8_t data[3]; public: // 符号位读写 bool get_sign() const { return (data[0] >> 7) & 0x1; } void set_sign(bool sign) { data[0] = sign ? (data[0] | 0x80) : (data[0] & ~0x80); } // 指数位读写 uint8_t get_exponent() const { return (data[0] >> 1) & 0x3F; } void set_exponent(uint8_t exp) { data[0] = (data[0] & 0x81) | ((exp & 0x3F) << 1); } // 尾数位读写 uint32_t get_mantissa() const { return ((uint32_t)(data[0] & 0x1) << 16) | ((uint32_t)data[1] << 8) | data[2]; } void set_mantissa(uint32_t mant) { data[0] = (data[0] & 0xFE) | ((mant >> 16) & 0x1); data[1] = (mant >> 8) & 0xFF; data[2] = mant & 0xFF; } };
该方案可以100%保证类的大小为3字节,且内存布局完全可控,不受编译器实现差异影响。
内容的提问来源于stack exchange,提问作者vanderwaal
相关产品推荐
相关产品推荐

