我有来自服务器的数据包,该数据包在嵌入式系统中解析。我需要以非常有效的方式解析它,避免内存问题,如重叠,破坏我的记忆和其他变量。
数据包具有“String A:String B:String C”的结构。
例如,这里收到的数据包是由使用分隔符“:”分隔的三个部分组合而成的,所有这些部分必须是来自结构的可访问部分。
这是最有效和最安全的方法。
A.-创建一个具有属性(partA,PartB PartC)的结构,其大小与基于避免的标准大小超过数据包源的大小,并附加一个索引,每个部分的长度以避免的方式提取垃圾,这部分长度指标可以小于或等于300(即:B部分)。
typedef struct parsedPacket_struct {
char partA[2];int len_partA;
char partB[300];int len_partB;
char partC[2];int len_partC;
}parsedPacket;
这里的问题是我浪费内存,因为每个结构都应该将数据包内容复制到每个结构中,有没有办法只保存每个部分的基地址并仍然使用len_partX。
答案 0 :(得分:4)
如何用0替换(:),并在末尾添加一个null - 然后你有三个char *来传递。您将需要处理0个长度字符串,但这可能会解决它
答案 1 :(得分:1)
为避免损坏内存和其他变量,通常将大数据缓冲区声明为静态并将它们放在文件范围内,然后为它们分配单独的RAM段。让它们坐在堆栈上是任何嵌入式系统中的一个坏主意。
您需要考虑是否存在CPU的对齐要求以及代码是否应该是可移植的。编译器可以在该结构中的任何位置随意添加任意数量的填充字节,这意味着您可能无法执行此操作:
parsedPacket pp;
memcpy(&pp, raw_data, sizeof(parsedPacket )) ;
出于这个原因,结构通常是用于存储数据包的错误选择。最安全的解决方案是:
/* packet.h */
typedef struct parsedPacket_struct {
uint8_t* partA;
uint8_t* partB;
uint8_t* partC;
uint16_t len_partA;
uint16_t len_partB;
uint16_t len_partC;
}parsedPacket;
#define MAX_PART_A 2
#define MAX_PART_B 300
#define MAX_PART_C 2
void packet_receive (parsedPacket* packet);
/* packet.c */
static uint8 partA[MAX_PART_A];
static uint8 partB[MAX_PART_B];
static uint8 partC[MAX_PART_C];
void packet_receive (parsedPacket* packet)
{
/* receive data from server */
...
packet->len_partA = ...;
packet->len_partB = ...;
packet->len_partC = ...;
packet->partA = partA;
packet->partB = partB;
packet->partC = partC;
memcpy(partA, A_from_server, packet->len_partA);
memcpy(partB, B_from_server, packet->len_partB);
memcpy(partC, C_from_server, packet->len_partC);
}
如果需要,可以扩展为包含多个静态缓冲区,即每个缓冲区的静态数组。当您在嵌入式系统中处理大量数据时,您永远不能允许程序随意堆叠缓冲区。必须在程序设计期间确定接收数据包的最大副本量。
答案 2 :(得分:0)
每个len_partN
的类型应该是一个最长可达partN
的类型。 E.g:
typedef struct parsedPacket_struct {
char partA[300];unsigned short len_partA; // unsigned shorts have < 32k distinct values
char partB[300];unsigned short len_partB;
char partC[300];unsigned short len_partC;
}parsedPacket;
这似乎是一个设计决定。如果您希望结构易于创建,请使用上述方法,但要注意其缺点(例如“如果B有超过300个字符会怎么样?”)。
答案 3 :(得分:0)
我不确定你为什么认为你的方法浪费记忆力,但如果我感觉特别黑客,我会怎么做:
typedef struct {
char *a, *b, *c;
char data[1]; // or 0 if your compiler lets you, or nothing in C99
} parsedPacket;
这称为灵活的阵列成员。基本上,当您为结构分配内存时,请执行以下操作:
parsedPacket *p = malloc(offsetof(parsedPacket, data[N]));
上面的N变成了数组所需的数据量,即你读取的字符串的长度。这会分配结构,以便data
成员具有足够的大小来容纳整个数据字符串。然后,将您收到的字符串复制到此成员中,将':'
字符替换为'\0'
,并将a
设置为第一个字符串(即p->a = p->data
),b
到第二个(p->b = p->data + strlen(p->a) + 1
)和c
到第三个。当然,您可以通过一次完成所有操作来简化此过程:
size_t current = 0;
p->a = p->data;
p->b = p->c = NULL;
while(1)
{
int i = getc();
if(i == '\n' || i == EOF) break; // or whatever end conditions you expect
if(i == ':')
{
p->data[current] = '\0';
++current;
if(p->b == NULL) p->b = &p->data[current];
else if(p->c == NULL) p->c = &p->data[current];
else /* error */;
}
else
{
p->data[current] = i;
}
}