安全结构嵌入式系统

时间:2011-03-10 20:46:14

标签: c struct embedded memory-management

我有来自服务器的数据包,该数据包在嵌入式系统中解析。我需要以非常有效的方式解析它,避免内存问题,如重叠,破坏我的记忆和其他变量。

数据包具有“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。

4 个答案:

答案 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;
      }
  }