将字节数组转换为含指针的结构体时原数组被修改的问题排查
问题描述
我想要将一个字节数组转换为包含两个指针的结构体,但每次设置指针时,原字节数组都会被修改。通常我会使用末尾的柔性数组(如char name[])来处理这类情况,但由于该结构体中存在两个动态大小的字段,无法采用这种方式。
我也尝试过内存分配(见注释代码),但因为字节数组已包含所需的全部数据,我认为无需进行动态分配。请问我忽略了什么问题?
#include <stdio.h> #include <stdint.h> #include <string.h> #include <stdlib.h> typedef struct { uint8_t mac[6]; } __attribute__ ((packed)) mac_t; typedef struct { char type; uint16_t interval; uint16_t window; uint8_t name_length; uint8_t macs_length; char* name; mac_t* macs; } __attribute__ ((packed)) set_config_t; int main() { const uint8_t byte[] = {0x01, 0x02, 0x00, 0x03, 0x00, 0x05, 0x01, 'T', 'e', 's', 't', '\0', 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; printf("byte array before casting: "); for(int i = 0; i < sizeof(byte); i++) { printf("0x%02x ", byte[i]); } printf("\n"); set_config_t* data = (set_config_t*) byte; data->name = &byte[7]; data->macs = &byte[12]; //data->name = malloc(sizeof(data->name_length)); //data->macs = malloc(sizeof(data->macs_length) * sizeof(mac_t)); //memcpy(data->name, &byte[7], data->name_length); //memcpy(data->macs, &byte[12], data->macs_length * sizeof(mac_t)); printf("byte array after casting: "); for(int i = 0; i < sizeof(byte); i++) { printf("0x%02x ", byte[i]); } printf("\n\n"); printf("Sizeof byte %d\n", sizeof(byte)); printf("Sizeof set_scan_config_t %d\n", sizeof(set_config_t)); printf("type: %d\n", data->type); printf("interval: %d\n", data->interval); printf("window: %d\n", data->window); printf("name_length: %d\n", data->name_length); printf("macs_length: %d\n", data->macs_length); printf("name: %s", data->name); return 0; }
程序运行输出:
byte array before casting: 0x01 0x02 0x00 0x03 0x00 0x05 0x01 0x54 0x65 0x73 0x74 0x00 0xaa 0xbb 0xcc 0xdd 0xee 0xff byte array after casting: 0x01 0x02 0x00 0x03 0x00 0x05 0x01 0x47 0x20 0x61 0x95 0xfd 0x7f 0x00 0x00 0x4c 0x20 0x61 Sizeof byte 18 Sizeof set_scan_config_t 23 type: 1 interval: 2 window: 3 name_length: 5 macs_length: 1 name: G a��
问题根源
- 你错误地将只读字节数组
byte直接强制转换为set_config_t*指针,并修改结构体的指针成员。 set_config_t结构体在64位系统下总大小为23字节(前5个固定字段占7字节,两个指针成员各占8字节),但原字节数组仅18字节。结构体的name和macs指针成员会占用原字节数组从第7位开始的内存:name指针占用偏移7-14的8字节macs指针占用偏移15-22的8字节
- 当你给
data->name和data->macs赋值时,本质是把指针的地址值直接写入原字节数组的内存区域,直接覆盖了数组中存储的原始数据(比如'T'、'e'等字符),这就是数组内容被修改的核心原因。
解决方案
不需要动态分配内存,只需创建独立的set_config_t结构体实例,将原字节数组中的固定字段解析到结构体中,再让结构体的指针成员直接指向字节数组中对应的数据区域即可,完全不会修改原数组内容。
修正后的代码
#include <stdio.h> #include <stdint.h> #include <string.h> #include <stdlib.h> typedef struct { uint8_t mac[6]; } __attribute__ ((packed)) mac_t; typedef struct { char type; uint16_t interval; uint16_t window; uint8_t name_length; uint8_t macs_length; char* name; mac_t* macs; } __attribute__ ((packed)) set_config_t; int main() { const uint8_t byte[] = {0x01, 0x02, 0x00, 0x03, 0x00, 0x05, 0x01, 'T', 'e', 's', 't', '\0', 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; printf("byte array: "); for(int i = 0; i < sizeof(byte); i++) { printf("0x%02x ", byte[i]); } printf("\n"); // 创建独立的结构体实例,而非直接转换原数组 set_config_t data; // 从字节数组中解析固定长度字段 data.type = byte[0]; // 若字节序与系统不一致,需自行转换,此处假设匹配 memcpy(&data.interval, &byte[1], sizeof(data.interval)); memcpy(&data.window, &byte[3], sizeof(data.window)); data.name_length = byte[5]; data.macs_length = byte[6]; // 让指针直接指向原数组中的对应数据区域 data.name = (char*)&byte[7]; data.macs = (mac_t*)&byte[12]; printf("\nSizeof byte %d\n", sizeof(byte)); printf("Sizeof set_config_t %d\n", sizeof(set_config_t)); printf("\ntype: %d\n", data.type); printf("interval: %d\n", data.interval); printf("window: %d\n", data.window); printf("name_length: %d\n", data.name_length); printf("macs_length: %d\n", data.macs_length); printf("name: %s\n", data.name); // 验证原数组未被修改 printf("\nbyte array after operation: "); for(int i = 0; i < sizeof(byte); i++) { printf("0x%02x ", byte[i]); } printf("\n"); return 0; }
运行输出
byte array: 0x01 0x02 0x00 0x03 0x00 0x05 0x01 0x54 0x65 0x73 0x74 0x00 0xaa 0xbb 0xcc 0xdd 0xee 0xff Sizeof byte 18 Sizeof set_config_t 23 type: 1 interval: 2 window: 3 name_length: 5 macs_length: 1 name: Test byte array after operation: 0x01 0x02 0x00 0x03 0x00 0x05 0x01 0x54 0x65 0x73 0x74 0x00 0xaa 0xbb 0xcc 0xdd 0xee 0xff
内容的提问来源于stack exchange,提问作者Manuel
相关产品推荐
相关产品推荐

