bit-field in CXX

本文深入探讨了C++中位字段的使用,包括其语法、属性及如何在类定义中声明带明确大小的成员。通过实例说明了位字段如何占用内存,并解释了匿名位字段的特殊用途。

bit-field in CXX

Declares a class data member with explicit size, in bits. Adjacent bit field members may be packed to share and straddle the individual bytes.

A bit filed declaration is a class data member declaration which uses the following declarator:

identifier(optional) attr(optional) : size (1)

identifier(optional) attr(optional) : size brace-or-equal-initializer (2) (since C++ 20)

The type of the bit field is introduced by the decl-specifier-seq of the declaration syntax.

  • attr(C++11) - optional sequence of any number of attributes.
  • identifier - the name of the bit field that it being declared. The name is optional: nameless bit-fields introduce the specified number of bits of padding.
  • size - an integral constant expression with a value greater or equal to zero. When greater than zero. this is the number of bits that this bit field will occupy. The value zero is only allowed for nameless bit-fields and has special meaning: it specifics that the next bit field in the class definition will begin at an allocation unit’s boundary.
  • brace-or-equal-initialize - default member initializer to be used with this bit field.

Let’s take an example:

struct S {
 // three-bit unsigned field,
 // allowed values are 0...7
 unsigned int b : 3;
};
struct S {
    // will usually occupy 2 bytes:
    // 3 bits: value of b1
    // 2 bits: unused
    // 6 bits: value of b2
    // 2 bits: value of b3
    // 3 bits: unused
    unsigned char b1 : 3, : 2, b2 : 6, b3 : 2;
};
struct S {
    // will usually occupy 2 bytes:
    // 3 bits: value of b1
    // 5 bits: unused
    // 6 bits: value of b2
    // 2 bits: value of b3
    unsigned char b1 : 3;
    unsigned char :0; // start a new byte
    unsigned char b2 : 6;
    unsigned char b3 : 2;
};

For more information:

https://en.cppreference.com/w/cpp/language/bit_field

请分析下面的代码,将arc_code、arc_code1、arc_code2、arc_code3、arc_code4、arc_code5等单独定义成32位联合体,并详细注释位域信息 重构代码,并详细注释代码,特别是位操作, 联合体操作在HDDMArc::readme_pb进行赋值操作,最后给出所有的函数的完整的全部代码 /* ######################################################################################################### // // File speedidx : HDDMArc.cxx // // Last Updated: 2025/10/03 10:38 // // ########################################################################################################*/ #include "std_to_string.h" #include "HDDMArc.h" #include "HEXDataException.h" // ========================================================================================================= // 构造函数 // ========================================================================================================= HDDMArc::HDDMArc() { // 初始化arc_code字段 this->arc_code = (this->arc_code & 0xFE00) | // 保留bit9-15 (0xFFC0 << 16); // 设置bit16-31为0xFFC0 this->arc_code = (this->arc_code & 0xC0FFFF00) | // 清除bit8-15,保留bit16-17 0x00000000; // 设置bit8-15为0 // 初始化arc_code1字段 this->arc_code1 = (this->arc_code1 & 0xFFFF0000) | // 保留bit16-31 0x0000FFFF; // 设置bit0-15为0xFFFF this->arc_code1 &= 0x0000FFFF; // 清除bit16-31 // 初始化arc_code2字段 this->arc_code2 = 0xFFF0FFF; // 设置固定值 // 初始化arc_code3字段 this->arc_code3 = (this->arc_code3 & 0xFFFFFFF0) | // 保留bit4-31,清除bit0-3 (0x3FFF0); // 设置bit4-19 this->arc_code3 |= (0xFFFC << 16); // 设置bit20-31 // 初始化arc_code4字段 this->arc_code4 = (this->arc_code4 & 0xFFFFFE00) | // 保留bit9-31,清除bit0-8 (0x7FE00); // 设置bit9-19 this->arc_code4 |= (0xFFF8 << 16); // 设置bit20-31 // 初始化arc_code5字段 this->arc_code5 = (this->arc_code5 & 0xFFFFFFFC) | // 保留bit2-31,清除bit0-1 (0x3FFC); // 设置bit2-15 this->arc_code5 = (this->arc_code5 & 0xF0003FFF) | // 保留bit0-13和bit28-31 (0xFFF8000); // 设置bit14-27 this->arc_code5 = (this->arc_code5 & 0xF0FFFFFF); // 保留bit0-27,清除bit28-31 // 构造 HDDMArc 字段变量 this->m_arcIndex = 0; this->m_speedidx = 0; this->m_deviceid = 0; this->m_graphid = 0; this->m_directional = 0; this->m_buffered21 = 0; this->m_buffered20 = 0; this->m_pseudo = 0; this->m_latePseudo = 0; this->m_element = 0; this->m_frompin = 0; this->m_topin = 0; this->arc_rwflags = 0; } // ========================================================================================================= // 1. PB数据读取函数 // ========================================================================================================= void HDDMArc::readme_pb( std::istream &stream, HDDMDevice *hddmDevice) { // // (1) 如果需要使用Xng标记,先读取3字节标记 // if (HDDMDeviceDump::useXngMarks) { stream.read(HDDMDeviceDump::markBuffer, 3); } // // (2) 创建并解析Protobuf消息 // HDDMXng::Arc arc_msg; hddmDevice->readMessage(stream, arc_msg); // // (3) 获取描述Descriptor对象和反射Reflection对象 // const google::protobuf::Descriptor *descriptor = arc_msg.GetDescriptor(); const google::protobuf::Reflection *reflection = arc_msg.GetReflection(); // // (4) 提取Protobuf字段 // // (4-1) 读取 flags 字段 (protobuf 字段1) // uint32 flags = 0; const google::protobuf::FieldDescriptor *flags_field = descriptor->FindFieldByName("flags"); if (flags_field && reflection->HasField(arc_msg, flags_field)) { flags = reflection->GetUInt32(arc_msg, flags_field); // 设置bit0为1,表示flags字段已读取 this->arc_rwflags |= 1 << 0; } // // (4-2) 读取 sitetype 字段 (protobuf 字段2) // uint32 sitetype = 0; const google::protobuf::FieldDescriptor *sitetype_field = descriptor->FindFieldByName("sitetype"); if (sitetype_field && reflection->HasField(arc_msg, sitetype_field)) { sitetype = reflection->GetUInt32(arc_msg, sitetype_field); // 设置bit1为1,表示flags字段已读取 this->arc_rwflags |= 1 << 1; } // // (4-3) 读取 element 字段 (protobuf 字段3) // uint32 element = 0; const google::protobuf::FieldDescriptor *element_field = descriptor->FindFieldByName("element"); if (element_field && reflection->HasField(arc_msg, element_field)) { element = reflection->GetUInt32(arc_msg, element_field); // 设置bit2为1,表示element字段已读取 this->arc_rwflags |= 1 << 2; } // // (4-4) 读取 indexinelement 字段 (indexinelement 字段4) // uint32 indexinelement = 0; const google::protobuf::FieldDescriptor *indexinelement_field = descriptor->FindFieldByName("indexinelement"); if (indexinelement_field && reflection->HasField(arc_msg, indexinelement_field)) { indexinelement = reflection->GetUInt32(arc_msg, indexinelement_field); // 设置bit3为1,表示indexinelement字段已读取 this->arc_rwflags |= 1 << 3; } // // (4-5) 读取 frompin 字段 (frompin 字段5) // uint32 frompin = 0; const google::protobuf::FieldDescriptor *frompin_field = descriptor->FindFieldByName("frompin"); if (frompin_field && reflection->HasField(arc_msg, frompin_field)) { frompin = reflection->GetUInt32(arc_msg, frompin_field); // 设置bit4为1,表示frompin字段已读取 this->arc_rwflags |= 1 << 4; } // // (4-6) 读取 topin 字段 (topin 字段6) // uint32 topin = 0; const google::protobuf::FieldDescriptor *topin_field = descriptor->FindFieldByName("topin"); if (topin_field && reflection->HasField(arc_msg, topin_field)) { topin = reflection->GetUInt32(arc_msg, topin_field); // 设置bit5为1,表示topin字段已读取 this->arc_rwflags |= 1 << 5; } // // (4-7) 读取 graphid 字段 (graphid 字段7) // uint32 graphid = 0; const google::protobuf::FieldDescriptor *graphid_field = descriptor->FindFieldByName("graphid"); if (graphid_field && reflection->HasField(arc_msg, graphid_field)) { graphid = reflection->GetUInt32(arc_msg, graphid_field); // 设置bit6为1,表示graphid字段已读取 this->arc_rwflags |= 1 << 6; } // // (4-8) 读取 speedidx 字段 (speedidx 字段8) // uint32 speedidx = 0; const google::protobuf::FieldDescriptor *speedidx_field = descriptor->FindFieldByName("speedidx"); if (speedidx_field && reflection->HasField(arc_msg, speedidx_field)) { speedidx = reflection->GetUInt32(arc_msg, speedidx_field); // 设置bit7为1,表示speedidx字段已读取 this->arc_rwflags |= 1 << 7; } // // (4-9) 读取 wire0 字段 (wire0 字段9) // uint32 wire0 = 0; const google::protobuf::FieldDescriptor *wire0_field = descriptor->FindFieldByName("wire0"); if (wire0_field && reflection->HasField(arc_msg, wire0_field)) { uint32 wire0 = reflection->GetUInt32(arc_msg, wire0_field); // 设置bit8为1,表示wire0字段已读取 this->arc_rwflags |= 1 << 8; } // // (4-10) 读取 wire1 字段 (wire1 字段10) // uint32 wire1 = 0; const google::protobuf::FieldDescriptor *wire1_field = descriptor->FindFieldByName("wire1"); if (wire1_field && reflection->HasField(arc_msg, wire1_field)) { wire1 = reflection->GetUInt32(arc_msg, wire1_field); // 设置bit9为1,表示wire1字段已读取 this->arc_rwflags |= 1 << 9; } // // (5) 解析消息字段到结构体成员 // // 位域映射逻辑: // flags[1] -> arc_code低16位 // graphid[7] -> arc_code高16位 // sitetype[2] -> arc_code4高10位(bit9-18) // element[3] -> arc_code4低9位(bit0-8) // indexinelement[4] -> arc_code5低12位 // frompin[5] -> arc_code3中14位(bit4-17) // topin[6] -> arc_code3高16位(bit18-31) // speedidx[8] -> arc_code1低16位 // wire0[9] -> arc_code2低16位 // wire1[10] -> arc_code2高16位 // 基础字段直接映射 this->arc_code = (graphid << 16) | (flags & 0xFFFF); // 条件分支 if (flags & 0x04)// 特殊模式 { this->arc_code1 = speedidx; this->arc_code2 = (wire1 << 16) | wire0; this->arc_code3 = (topin << 18) | (frompin << 4); } else // 常规模式 { this->arc_code3 = (topin << 18) | (frompin << 4); this->arc_code4 = (sitetype << 9) | (element & 0x1FF); this->arc_code5 = indexinelement & 0xFFF; } // // (6) 重构 HDDMArc 字段变量 // this->m_arcIndex = (this->arc_code1 >> 16) & 0xFFFF; this->m_speedidx = (this->arc_code1 & 0xFFFF); this->m_deviceid = (this->arc_code5 >> 4) & 0xF; this->m_graphid = (this->arc_code >> 16) & 0xFFFF; this->m_directional = (this->arc_code >> 5) & 0x1; this->m_buffered21 = (this->arc_code >> 6) & 0x1; this->m_buffered20 = (this->arc_code >> 7) & 0x1; this->m_pseudo = (this->arc_code >> 3) & 0x1; this->m_latePseudo = (this->arc_code >> 4) & 0x1; this->m_element = (this->arc_code4 >> 9) & 0x3FF; this->m_frompin = (this->arc_code3 >> 4) & 0x3FFF; this->m_topin = (this->arc_code3 >> 18) & 0x3FFF; // 校验 flags 字段内容 #ifdef CHECK_RW_PROTOBUF { uint32 flags_rev = 0; uint32 sitetype_rev = 0; uint32 element_rev = 0; uint32 indexinelement_rev = 0; uint32 frompin_rev = 0; uint32 topin_rev = 0; uint32 graphid_rev = 0; uint32 speedidx_rev = 0; uint32 wire0_rev = 0; uint32 wire1_rev = 0; flags_rev = this->arc_code & 0xFFFF; graphid_rev = (this->arc_code >> 16) & 0xFFFF; frompin_rev = (this->arc_code3 >> 4) & 0x3FFF; topin_rev = (this->arc_code3 >> 18) & 0x3FFF; assert(flags_rev == flags); assert(graphid_rev == graphid); assert(frompin_rev == frompin); assert(topin_rev == topin); // 反向位域映射 if (this->arc_code & 0x04) // 特殊模式 { speedidx_rev = this->arc_code1 & 0xFFFF; wire0_rev = this->arc_code2 & 0xFFFF; wire1_rev = (this->arc_code2 >> 16) & 0xFFFF; assert(speedidx_rev == speedidx); assert(wire0_rev == wire0); assert(wire1_rev == wire1); } else // 常规模式 { sitetype_rev = (this->arc_code4 >> 9) & 0x3FF; element_rev = this->arc_code4 & 0x1FF; indexinelement_rev = this->arc_code5 & 0xFFF; assert(sitetype_rev == sitetype); assert(element_rev == element); assert(indexinelement_rev == indexinelement); } } #endif } // ========================================================================================================= // 2. PB数据写入函数 // ========================================================================================================= void HDDMArc::writeme_pb( std::ofstream &stream) { uint32 flags = 0; uint32 sitetype = 0; uint32 element = 0; uint32 indexinelement = 0; uint32 frompin = 0; uint32 topin = 0; uint32 graphid = 0; uint32 speedidx = 0; uint32 wire0 = 0; uint32 wire1 = 0; // // (1) 如果需要使用Xng标记,写入3字节标记 // if (HDDMDeviceDump::useXngMarks) { stream.write("PIN", 3); } // // (2) 创建 HDDMArc protobuf消息 // HDDMXng::Arc arc_msg; // // (3) 获取 描述 Descriptor 对象 和 反射 Reflection 对象 // const google::protobuf::Descriptor *descriptor = arc_msg.GetDescriptor(); const google::protobuf::Reflection *reflection = arc_msg.GetReflection(); // // (4) 填充 protobuf 消息数据 // flags = this->arc_code & 0xFFFF; graphid = (this->arc_code >> 16) & 0xFFFF; frompin = (this->arc_code3 >> 4) & 0x3FFF; topin = (this->arc_code3 >> 18) & 0x3FFF; // 反向位域映射 if (this->arc_code & 0x04) // 特殊模式 { speedidx = this->arc_code1 & 0xFFFF; wire0 = this->arc_code2 & 0xFFFF; wire1 = (this->arc_code2 >> 16) & 0xFFFF; } else // 常规模式 { sitetype = (this->arc_code4 >> 9) & 0x3FF; element = this->arc_code4 & 0x1FF; indexinelement = this->arc_code5 & 0xFFF; } // // (4-1) 设置 flags 字段 (protobuf 字段1) // const google::protobuf::FieldDescriptor *flags_field = descriptor->FindFieldByName("flags"); if (flags_field && ((this->arc_rwflags >> 0) & 1)) // 获取protobuf读写标志 { reflection->SetUInt32(&arc_msg, flags_field, flags); } // // (4-2) 设置 sitetype 字段 (protobuf 字段2) // const google::protobuf::FieldDescriptor *sitetype_field = descriptor->FindFieldByName("sitetype"); if (sitetype_field && ((this->arc_rwflags >> 1) & 1)) // 获取protobuf读写标志 { reflection->SetUInt32(&arc_msg, sitetype_field, sitetype); } // // (4-3) 设置 element 字段 (protobuf 字段3) // const google::protobuf::FieldDescriptor *element_field = descriptor->FindFieldByName("element"); if (element_field && ((this->arc_rwflags >> 2) & 1)) // 获取protobuf读写标志 { reflection->SetUInt32(&arc_msg, element_field, element); } // // (4-4) 设置 indexinelement 字段 (indexinelement 字段4) // const google::protobuf::FieldDescriptor *indexinelement_field = descriptor->FindFieldByName("indexinelement"); if (indexinelement_field && ((this->arc_rwflags >> 3) & 1)) // 获取protobuf读写标志 { reflection->SetUInt32(&arc_msg, indexinelement_field, indexinelement); } // // (4-5) 设置 frompin 字段 (frompin 字段5) // const google::protobuf::FieldDescriptor *frompin_field = descriptor->FindFieldByName("frompin"); if (frompin_field && ((this->arc_rwflags >> 4) & 1)) // 获取protobuf读写标志 { reflection->SetUInt32(&arc_msg, frompin_field, frompin); } // // (4-6) 设置 topin 字段 (topin 字段6) // const google::protobuf::FieldDescriptor *topin_field = descriptor->FindFieldByName("topin"); if (topin_field && ((this->arc_rwflags >> 5) & 1)) // 获取protobuf读写标志 { reflection->SetUInt32(&arc_msg, topin_field, topin); } // // (4-7) 设置 graphid 字段 (graphid 字段7) // const google::protobuf::FieldDescriptor *graphid_field = descriptor->FindFieldByName("graphid"); if (graphid_field && ((this->arc_rwflags >> 6) & 1)) // 获取protobuf读写标志 { reflection->SetUInt32(&arc_msg, graphid_field, graphid); } // // (4-8) 设置 speedidx 字段 (speedidx 字段8) // const google::protobuf::FieldDescriptor *speedidx_field = descriptor->FindFieldByName("speedidx"); if (speedidx_field && ((this->arc_rwflags >> 7) & 1)) // 获取protobuf读写标志 { reflection->SetUInt32(&arc_msg, speedidx_field, speedidx); } // // (4-9) 设置 wire0 字段 (wire0 字段9) // const google::protobuf::FieldDescriptor *wire0_field = descriptor->FindFieldByName("wire0"); if (wire0_field && ((this->arc_rwflags >> 8) & 1)) // 获取protobuf读写标志 { reflection->SetUInt32(&arc_msg, wire0_field, wire0); } // // (4-10) 设置 wire1 字段 (wire1 字段10) // const google::protobuf::FieldDescriptor *wire1_field = descriptor->FindFieldByName("wire1"); if (wire1_field && ((this->arc_rwflags >> 9) & 1)) // 获取protobuf读写标志 { reflection->SetUInt32(&arc_msg, wire1_field, wire1); } // // (5) 写入protobuf消息 // HDDMDevice hddmDevice; hddmDevice.writeMessage(stream, arc_msg); // // (6) 刷新输出流 // stream.flush(); } // ========================================================================================================= // 3. 调试信息打印函数 // ========================================================================================================= void HDDMArc::print( std::ostream &stream, const std::string& stdFileName) { // 预计算常用值 uint32 m_arcIndex = (this->arc_code1 >> 16) & 0xFFFF; uint32 m_speedidx = this->arc_code1 & 0xFFFF; uint32 m_deviceid = (this->arc_code5 >> 4) & 0xF; uint32 m_graphid = (this->arc_code >> 16) & 0xFFFF; uint32 m_directional = (this->arc_code >> 5) & 0x1; // 批量输出减少I/O调用 stream << stdFileName << "ARC m_arcIndex : " << m_arcIndex << " m_speedidx : " << m_speedidx << " m_deviceid : " << m_deviceid << " m_graphid : " << m_graphid << " m_directional : " << m_directional << '\n'; // 第二组字段 uint32 m_buffered21 = (this->arc_code >> 6) & 0x1; uint32 m_buffered20 = (this->arc_code >> 7) & 0x1; uint32 m_pseudo = (this->arc_code >> 3) & 0x1; uint32 m_latePseudo = (this->arc_code >> 4) & 0x1; stream << "m_buffered21 : " << m_buffered21 << " m_buffered20 : " << m_buffered20 << " m_pseudo : " << m_pseudo << " m_latePseudo : " << m_latePseudo << '\n'; // 第三组字段 uint32 m_element = (this->arc_code4 >> 9) & 0x3FF; uint32 m_frompin = (this->arc_code3 >> 4) & 0x3FFF; uint32 m_topin = (this->arc_code3 >> 16) & 0x3FFF; stream << "m_element : " << m_element << " m_frompin : " << m_frompin << " m_topin : " << m_topin << '\n'; } // ========================================================================================================= // 4. 获取组件内时序弧索引 // ========================================================================================================= uint16 HDDMArc::getArcIndexInElement(void) { uint16 index = this->arc_code5 & 0xFFF; // 低12位存储索引 return index; } // ========================================================================================================= // 5. 获取组件索引 // ========================================================================================================= uint32 HDDMArc::getElement(void) { uint32 element_id = (this->arc_code4 >> 9) & 0x3FF; return element_id; } // ========================================================================================================= // 6. 获取起始引脚 // ========================================================================================================= uint32 HDDMArc::getFromElementPin(void) { uint32 pin_id = (this->arc_code3 >> 4) & 0x3FFF; return pin_id; } // ========================================================================================================= // 7. 获取函数弧索引 // ========================================================================================================= uint32 HDDMArc::getIndex(void) { return (this->arc_code1 >> 16) & 0xFFFF; } // ========================================================================================================= // 8. 获取目标引脚 // ========================================================================================================= uint32 HDDMArc::getToElementPin(void) { uint32 pin_id = (arc_code3 >> 18) & 0x3FFF; return pin_id; } // ========================================================================================================= // 9. 获取位置类型 // ========================================================================================================= uint32 HDDMArc::getSiteType(void) { uint32 site_id = (arc_code4 >> 9) & 0x3FF; return site_id; } // ========================================================================================================= // 新增加函数 --- 设置时序弧索引 // 时序弧索引定义: uint32 m_arcIndex = (this->arc_code1 >> 16) & 0xFFFF; // ========================================================================================================= void HDDMArc::setIndex(uint32 nIndex) { this->arc_code1 = this->arc_code1 | (nIndex << 16); this->m_arcIndex = (this->arc_code1 >> 16) & 0xFFFF; }
11-06
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值