在PC中构建嵌入式目标的{C}结构

时间:2015-05-14 02:05:00

标签: c xml parsing embedded

我需要从XML中提取数据并将其作为结构链接到C嵌入式项目。

XML在运行时不可用。 (没有文件系统,文件太大,安全原因)。所以我必须解析它并在我的PC预链接上生成结构。

如果我使用二进制数据,那么它必须与目标中的格式相同(即使是来自同一供应商的编译器,对吧?)。你会生成一个在项目中编译的c文件吗?有更简单的方法吗?

struct myStruct s = generateMyStruct("file.xml");

s.generateCfile("convertedXml.c");

1 个答案:

答案 0 :(得分:1)

控制结构布局

如果您使用<stdint.h>中的数据类型(例如int32_tuint8_t)并为struct中的每个字节定义字段,以使类型与其大小保持一致(例如,32位值应该是4字节对齐,16位值应该是2字节对齐的),那么你应该没问题,你的结构布局应该在两个平台上都匹配。

例如,不要写这样的结构:

typedef struct {
    uint8_t a;
    uint32_t b;
} Foo;

因为编译器可能会奇怪地填充ab之间的三个字节,因此b是从结构开始的4个字节的倍数。相反,将这些填充字节放在自己:

typedef struct {
    uint8_t a;
    uint8_t padding[3];
    uint32_t b;
} Foo;

有时编译器会有扩展来控制打包和对齐。在使用之前,请确保两个编译器都具有这些扩展。或者只是忽略扩展并手动填充数据,如上所述。

生成C初始化代码

一旦编写了创建结构的代码并使用从XML解析的数据填充它,就可以编写函数generateCfile来生成初始化文件。它不仅应该传递输出文件或文件名,还应该传递给初始化结构的指针。 (s.generateCfile("convertedXml.c");实际上是C ++语法,而不是C.)

void generateCfile(const struct Foo* s, const char* filename) {
    FILE* fp = fopen(filename, "w");

    fprintf(fp, "#include \"InitFoo.h\"\n\n");
    fprintf(fp, "const struct Foo kInitFoo = {\n");
    fprintf(fp, "    %u, { 0, 0, 0 }, %u\n", s->a, s->b);
    fprintf(fp, "};\n");

    fclose(fp);
}

通过简单地使用标准初始化器语法,您不必担心平台之间的字节顺序差异。

您应该使用生成的C文件和一个声明常量结构的短头文件:

#ifndef InitFoo_h
#define InitFoo_h

#include "Foo.h"

extern const struct Foo kInitFoo;

#endif
BTW,没有任何迹象表明代码生成器必须使用与目标编译器相同的语言编写。我经常在Python中编写输出C ++的代码生成器。

# Remember to double braces that should be in the output.
TEMPLATE = '''
#include "InitFoo.h"

const struct Foo kInitFoo = {{
    {a:d}, {{ 0, 0, 0 }}, {b:d}
}};
'''

def generateCfile(foo, filename):
    with open(filename, "w") as f:
        f.write(TEMPLATE.format(**foo));

# test code
generateCfile({"a": 15, "b": 45}, "convertedXml.c")

此外,像Python这样的高级语言往往更容易使用XML或JSON解析器。 YMMV。

对于任一代码生成器,并且在解析结构中给出a = 15和b = 45,您应该在convertedXml.c中得到它:

#include "InitFoo.h"

const struct Foo kInitFoo = {
    15, { 0, 0, 0 }, 45
};