在 PC 中为嵌入式目标构建 C 结构

Building in PC a C struct for an embedded target

我需要从 XML 和 link 中提取数据作为 C 嵌入式项目的结构。

XML 在运行时不可用。 (没有文件系统,文件太大,和安全原因)。所以我必须解析它并在我的 PC pre-linkedge.

上生成结构

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

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

s.generateCfile("convertedXml.c");

控制结构布局

如果您使用 <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

顺便说一句,代码生成器必须使用与目标编译器相同的语言来编写。我经常在 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
};