如何获取嵌套结构体引用,递归计算带位域C#结构体等效C大小?
问题:递归计算带嵌套结构体与自定义位域的C#结构体等效C语言打包大小
我正在编写一个C#函数,用于计算某一C#结构体若以C语言打包结构体(__attribute__((packed)))实现时的大小。由于C#原生不支持位域,我通过自定义BitfieldLengthAttribute来模拟位域逻辑,因此无法直接使用Marshal.SizeOf(my_struct)。
结构体定义示例
[StructLayout(LayoutKind.Sequential, Pack = 1)] public struct struct_b{// 对应C语言:typedef struct __attribute__((packed)){ [BitfieldLength(1)] public byte flag_a;// uint8_t flag_a :1; [BitfieldLength(1)] public byte flag_b;// uint8_t flag_b :1; [BitfieldLength(2)] public byte flag_c;// uint8_t flag_c :2; [BitfieldLength(1)] public byte flag_d;// uint8_t flag_d :1; [BitfieldLength(3)] public byte reserved;// uint8_t reserved :3; public float measure_1;//float measure_1 public float measure_2;//float measure_2 public UInt32 value_1; // uint32_t value_1; }// struct_b; [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct struct_a{ // 对应C语言:typedef struct __attribute__((packed)){ public Int16 i_value_a;// int16_t i_value_a; public struct_b struct_field_b; //struct_b struct_field_b; }// struct_a
现有实现与问题
我希望通过递归调用SizeInPackedBytes函数处理整个结构体,目前该函数能正确处理无嵌套的结构体,但无法处理包含嵌套结构体的场景。核心问题是:不知道如何从父结构体的FieldInfo中获取嵌套结构体的实例,以递归调用该函数。
现有函数的关键代码片段如下:
public static int SizeInPackedBytes(object structure, int i_start_idx, ref string str_parsed_struct){ int i_bitset_counter = 0; int i_num_bits = 0; int i_byte_index = 0; int i_aux = 0; bool b_is_struct = false; int i_field_idx = 0; FieldInfo[] field_info_array = structure.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); for (i_field_idx = 0; i_field_idx < field_info_array.Count(); i_field_idx++){ FieldInfo field_info = field_info_array[i_field_idx]; // 判断当前字段是否为嵌套结构体:结构体是ValueType,但不是基础类型或枚举 b_is_struct = (field_info.FieldType.IsValueType && !field_info.FieldType.IsPrimitive && !field_info.FieldType.IsEnum); if (b_is_struct){ // >>> 此处无法获取嵌套结构体实例,无法递归调用 // 尝试过错误写法:object nested_struct = field_local.GetValue(null); }else{ // 处理位域或普通字段的逻辑(已实现) // ... } } // ... return i_byte_index + (i_bitset_counter > 0 ? 1 : 0); }
我需要正确实现从FieldInfo获取嵌套结构体实例的逻辑,替换上述代码中的注释部分。
解决方案
要获取父结构体中嵌套结构体的实例,需要调用FieldInfo.GetValue()并传入父结构体的实例(即函数参数structure),而不是null(null仅适用于静态字段)。修正后的嵌套结构体处理逻辑如下:
if (b_is_struct){ // 1. 获取父结构体中当前嵌套结构体字段的实例 object nestedStructInstance = field_info.GetValue(structure); // 2. 递归计算嵌套结构体的打包大小,传入当前的起始偏移和解析字符串引用 int nestedSize = SizeInPackedBytes(nestedStructInstance, i_start_idx + i_byte_index, ref str_parsed_struct); // 3. 累加嵌套结构体的大小到总字节数 i_byte_index += nestedSize; // 4. 处理位域对齐:嵌套结构体是完整的字节块,若之前有未填满的位域,需补全字节 if (i_bitset_counter != 0){ i_byte_index++; i_bitset_counter = 0; } }
关键说明
GetValue(structure):因为嵌套结构体是父结构体的实例字段,必须传入父结构体的实例才能获取到对应的字段值,这是之前错误使用GetValue(null)的核心原因。- 递归调用:嵌套结构体本身可能包含位域或更深层次的嵌套,递归调用会自动处理这些场景。
- 位域对齐:由于嵌套结构体是完整的字节单元,若之前有未填满的位域(
i_bitset_counter != 0),需要先补全当前字节,再累加嵌套结构体的大小。
内容的提问来源于stack exchange,提问作者AtariTeen
相关产品推荐
相关产品推荐

