【问题标题】:Reliable string concatenation in embedded system using C language使用 C 语言的嵌入式系统中可靠的字符串连接
【发布时间】:2014-12-12 07:45:02
【问题描述】:

我目前正在编写一段代码,该代码将通过以太网将一些 XML 数据作为字符串发送。应该首先构造数据,以便将其发送到套接字。我正在使用 STM32F4xx 类型的微控制器并使用 IAR EWARM 嵌入式开发环境。

我一直在使用以下功能:

char* concat(char *s1, char *s2)
{
    size_t len1 = strlen(s1);
    size_t len2 = strlen(s2);
    char *result = malloc(len1+len2+1);//+1 for the zero-terminator
    //in real code you would check for errors in malloc here
    memcpy(result, s1, len1);
    memcpy(result+len1, s2, len2+1);//+1 to copy the null-terminator
    return result;
}

char* data = concat("<data>\n<items>\n<radar x=\"", "1"); 
data = concat(data, "\"></radar>\n<radar v=\"");
data = concat(data, "1");
data = concat(data, "\"></radar>\n</items>\n</data>");
len = strlen(data);

Socket_Send(data,len);

以太网服务器输出结果如下:

Send:(09:41:17) alive
Rec:(09:41:17)<data>
<items>
<radar x="1"></radar>
<radar v="1"></radar>
</items>
</data>
Send:(09:41:18) alive
Rec:(09:41:18)<data>
<items>
<radar x="1"></radar>
<radar v="1"></radar>
</items>
</data>
Send:(09:41:18) alive
Rec:(09:41:18)<data>

它正确发送数据 2 次,然后只写入 6 个字符。我该如何解决?任何帮助是极大的赞赏。提前谢谢..

编辑 1: 建议代码:

data = concat("<data>\n<items>\n<radar x=\"", "1"); 
char *tmp = data;
data = concat(data, "\"></radar>\n<radar v=\"");
free(tmp);
data = concat(data, "1");
data = concat(data, "\"></radar>\n</items>\n</data>");

len = strlen(data);

输出:

Send:(09:51:38) alive
Rec:(09:51:38)<data>
<items>
<radar x="1"></radar>
<radar v="1"></radar>
</items>
</data>
Send:(09:51:40) alive
Rec:(09:51:40)<data>
<items>
<radar x="1"></radar>
<radar v="1"></radar>
</items>
</data>
Send:(09:51:44) alive
Rec:(09:51:44)<data>
<items>
<radar x="1"></radar>
<radar v="1"></radar>
</items>
</data>
Send:(09:51:44) alive
Rec:(09:51:44)8 ¹Õ"></radar>
</items>
</data>
Send:(09:51:44) alive
Rec:(09:51:44)8 ¹Õ1"></radar>
</items>
</data>
Send:(09:51:45) alive
Rec:(09:51:45)8 ¹Õ1"></radar>
</items>
</data>
Send:(09:51:45) alive
Rec:(09:51:45)8 ¹Õ
Send:(09:51:45) alive
Rec:(09:51:45)8 ¹Õ
Send:(09:51:46) alive
Rec:(09:51:46)8 ¹Õ
Send:(09:51:46) alive
Rec:(09:51:46)8 ¹Õ

编辑 2(糟糕的解决方案):

char* data;
char* data1;
char* data2;
char* data3;
data1 = concat("<data>\n<items>\n<radar x=\"", "1"); 

data2 = concat(data1, "\"></radar>\n<radar v=\"");
free(data1);

data3 = concat(data2, "1");
free(data2);

data = concat(data3, "\"></radar>\n</items>\n</data>");
free(data3);

len = strlen(data);
Socket_Send(data,len);
free(data);

编辑 3(已解决):

当 XML 中的标签数量增加时,mem 泄漏按预期发生。正如人们所建议的那样,我尝试了 strcat 并且成功了。但是 strcpy 在我的编译器中不起作用。我强烈建议任何有同样问题的人使用 strcat。

【问题讨论】:

  • 我强烈建议将内存分配与算法分开。可悲的是,经验告诉我,如果程序在某处有一个函数,它返回一个指向动态分配内存的指针,几乎可以肯定会有内存泄漏。
  • 旁注:使用strcpy,strcat 而不是memcpy,memcpy。
  • 旁注#2:似乎不需要所有运行时串联。您所有的字符串都是常量,因此您不妨静态分配一个字符串。除了额外的安全性(通过避免动态内存分配/释放来实现)之外,您还将提高运行时性能,此外 - 保持它不变,因为在整个程序执行过程中字符串将驻留在相同的内存地址(没有意外的缓存影响等)。恒定的执行时间通常被认为是嵌入式系统中的一个关键方面。
  • 该实现已经提到了一个严重的内存泄漏问题,但是由于here 讨论的原因,字符串连接的方法可能会产生严重的性能影响 - 除了性能影响和不确定性之外首先是动态内存分配。

标签: c embedded concat strcat


【解决方案1】:

你在下面的调用中做了很多内存泄漏:

data = concat(data, "\"></radar>\n<radar v=\"");

纠正泄漏,您的程序应该可以按预期运行。

一种可能的解决方法:

{
  char *tmp = data;
  data = concat(data, "\"></radar>\n<radar v=\"");
  free(tmp);
}

同样在malloc之后,检查是否分配成功。

【讨论】:

  • 确保接收端也没有泄漏。我建议使用 valgrind 工具。
  • 接收方为通讯运营商
【解决方案2】:

根据需要的上下文,您还可以稍微重写 concat 函数。使其将可重新分配的缓冲区作为第一个参数。然后在 allocate 中释放它并返回新的 ptr。

char *concat(char *s1, char *s2)
{
    size_t len1 = s1 ? strlen(s1) : 0;
    size_t len2 = strlen(s2) + 1;
    char *result;

    result = malloc(len1 + len2);
    memcpy(result, s1, len1);
    memcpy(result + len1, s2, len2);
    free(s1);

    return result;
}

然后在你的其他代码中说:

size_t len;
char *data = NULL;

data = concat(data, "<data>\n<items>\n<radar x=\"");
data = concat(data, "1");
data = concat(data, "\"></radar>\n<radar v=\"");
data = concat(data, "1");
data = concat(data, "\"></radar>\n</items>\n</data>");


Socket_Send(data, strlen(data));
free(data);

顺便说一句,将数据转储到控制台有时会有所帮助——以验证它是否正确。执行以下操作:

#include <ctype.h>

void dump_txt(const char *buf, int len)
{
    int i;

    fprintf(stdout, "  ");
    for (i = 0; i < len; ++i)
        fprintf(stdout, "%c", isprint(buf[i]) ? buf[i] : '.');
    fprintf(stdout, "\n");
}

void dump(const char *buf, int len, int width)
{
    int i, k;

    for (i = 0; i < len; ++i) {
        if (i && !(i % width))
            dump_txt(buf + (i - width), width);
        fprintf(stdout, "%02x ", buf[i]);
    }
    k = i;
    for (k = i ; k % width; ++k)
        fprintf(stdout, "   ");
    dump_txt(buf + (i - (i % width)), k - i);
}

那么你可以说:

len = strlen(data);
dump(data, len + 1, 8); /* +1 to include trailing zero */
free(data);

这应该会给你类似的东西:

3c 64 61 74 61 3e 0a 3c   <data>.<
69 74 65 6d 73 3e 0a 3c   items>.<
72 61 64 61 72 20 78 3d   radar x=
22 31 22 3e 3c 2f 72 61   "1"></ra
64 61 72 3e 0a 3c 72 61   dar>.<ra
64 61 72 20 76 3d 22 31   dar v="1
22 3e 3c 2f 72 61 64 61   "></rada
72 3e 0a 3c 2f 69 74 65   r>.</ite
6d 73 3e 0a 3c 2f 64 61   ms>.</da
74 61 3e 00               ta>.

【讨论】:

  • 检查我的编辑。它现在有效。 +1 用于解释转储数据
猜你喜欢
  • 1970-01-01
  • 2016-05-18
  • 2010-09-12
  • 1970-01-01
  • 1970-01-01
  • 2013-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多