使用asn1c编译器处理ASN.1矩形/圆形结构的动态解码问题
解决ASN.1动态识别结构类型的解码问题
方案一:自定义标识头实现(符合你的初始思路)
编码步骤
- 定义1字节类型标识:比如
0x01代表矩形(Rectangle),0x02代表圆形(Circle) - 调用
uper_encode()对目标结构编码,得到二进制数据 - 将标识字节与编码后的数据拼接成完整发送缓冲区
示例代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "Mystructs.h" // asn1c生成的头文件 // 编码并添加标识头 int encode_with_header(void *struct_ptr, asn_TYPE_descriptor_t *td, uint8_t type_id, uint8_t **out_buf, size_t *out_len) { uint8_t *encoded_data = NULL; size_t encoded_len = 0; // 执行UPER编码 asn_enc_rval_t er = uper_encode(td, struct_ptr, NULL, (asn_app_consume_bytes_f)asn_write_out, &encoded_data); if (er.encoded == -1) { fprintf(stderr, "编码失败\n"); return -1; } encoded_len = er.encoded; // 分配缓冲区:1字节标识 + 编码数据 *out_buf = malloc(1 + encoded_len); if (!*out_buf) { free(encoded_data); return -1; } (*out_buf)[0] = type_id; memcpy(*out_buf + 1, encoded_data, encoded_len); *out_len = 1 + encoded_len; free(encoded_data); return 0; } // 使用示例:编码矩形 int main() { Rectangle_t rect = {.height = 100, .width = 200}; uint8_t *send_buf = NULL; size_t send_len = 0; if (encode_with_header(&rect, &asn_DEF_Rectangle, 0x01, &send_buf, &send_len) == 0) { // 此处添加发送逻辑 free(send_buf); } return 0; }
解码步骤
- 先读取第一个字节的标识值
- 根据标识选择对应的ASN.1类型描述符
- 调用
uper_decode()解码剩余的二进制数据
示例代码:
// 解码带标识头的数据 void decode_with_header(uint8_t *in_buf, size_t in_len) { if (in_len < 1) { fprintf(stderr, "数据长度不足\n"); return; } uint8_t type_id = in_buf[0]; uint8_t *encoded_data = in_buf + 1; size_t encoded_len = in_len - 1; asn_TYPE_descriptor_t *td = NULL; void *struct_ptr = NULL; // 根据标识匹配对应类型 switch (type_id) { case 0x01: td = &asn_DEF_Rectangle; struct_ptr = calloc(1, sizeof(Rectangle_t)); break; case 0x02: td = &asn_DEF_Circle; struct_ptr = calloc(1, sizeof(Circle_t)); break; default: fprintf(stderr, "未知类型标识\n"); return; } if (!struct_ptr) { fprintf(stderr, "内存分配失败\n"); return; } // 执行UPER解码 asn_dec_rval_t dr = uper_decode(NULL, td, &struct_ptr, encoded_data, encoded_len, 0, 0); if (dr.code != RC_OK) { fprintf(stderr, "解码失败\n"); td->free_struct(td, struct_ptr, 0); return; } // 处理解码结果 if (type_id == 0x01) { Rectangle_t *r = (Rectangle_t *)struct_ptr; printf("解码矩形:height=%d, width=%d\n", r->height, r->width); } else if (type_id == 0x02) { Circle_t *c = (Circle_t *)struct_ptr; printf("解码圆形:radius=%d\n", c->radius); } // 释放资源 td->free_struct(td, struct_ptr, 0); }
方案二:用ASN.1 CHOICE类型原生支持(更规范)
直接修改ASN.1定义,用CHOICE类型包装Rectangle和Circle,UPER编码会自动包含类型标识,无需手动处理头信息。
修改后的ASN.1代码:
Mystructs DEFINITIONS ::= BEGIN Rectangle ::= SEQUENCE { height INTEGER (0..255), width INTEGER (0..255) } Circle ::= SEQUENCE { radius INTEGER (0..255) } Shape ::= CHOICE { rectangle Rectangle, circle Circle } END
编码和解码示例
用asn1c重新编译后,直接使用Shape_t结构体:
#include <stdio.h> #include "Mystructs.h" // 编码示例 void encode_shape() { Shape_t shape = {.present = Shape_PR_rectangle}; shape.choice.rectangle.height = 100; shape.choice.rectangle.width = 200; uint8_t *encoded_data = NULL; asn_enc_rval_t er = uper_encode(&asn_DEF_Shape, &shape, NULL, (asn_app_consume_bytes_f)asn_write_out, &encoded_data); if (er.encoded != -1) { // 发送encoded_data free(encoded_data); } } // 解码示例 void decode_shape(uint8_t *recv_buf, size_t recv_len) { Shape_t *decoded_shape = NULL; asn_dec_rval_t dr = uper_decode(NULL, &asn_DEF_Shape, (void **)&decoded_shape, recv_buf, recv_len, 0, 0); if (dr.code == RC_OK) { switch (decoded_shape->present) { case Shape_PR_rectangle: printf("矩形:height=%d, width=%d\n", decoded_shape->choice.rectangle.height, decoded_shape->choice.rectangle.width); break; case Shape_PR_circle: printf("圆形:radius=%d\n", decoded_shape->choice.circle.radius); break; default: break; } ASN_STRUCT_FREE(asn_DEF_Shape, decoded_shape); } }
内容的提问来源于stack exchange,提问作者José
相关产品推荐
相关产品推荐

