【发布时间】:2013-04-28 12:00:45
【问题描述】:
我正在开发用于嵌入式系统的紧凑型调试输出/单元测试实用程序。
我创建了一个系统,可以通过串行端口以紧凑的方式将消息输出到 PC。 为了节省内存空间/串行端口带宽,我通过为它们提供唯一的 16 位 ID,从嵌入式系统中剥离了消息字符串。
这非常简单,因为我将所有消息都放在了 1 个列表中。一些宏会将其放入枚举中:
projectdefs.h:
#define MESSAGE_TABLE(MSG) \
MSG(HELLO, "Hello World!") \
MSG(TEST, "Second message #ID 1") \
MSG(TEST2, "Third message #ID 2")
messages.h:
#define MACRO_STR_CONCAT(a,b) a##b
#define MESSAGE_ENUM(codeName, str) MACRO_STR_CONCAT(MSG_, codeName)
typedef enum messageNumbers_e {
MESSAGE_TABLE(MESSAGE_ENUM),
MESSAGE_COUNT
};
#define MESSAGE(codeName) messageSend(MACRO_STR_CONCAT(MSG_, codeName), __LINE__, file_number);
通过串行端口传输的唯一数据是消息 ID、行号和文件号(注意;不是字符串!)。
我遇到的问题是如何使用 C 预处理器/编译器为每个文件分配唯一 ID。我不想将每个文件名字符串存储在嵌入式程序中。这会使用(过多)串行端口上的内存或带宽。
我的想法是用宏在每个文件中定义常量 file_number。我会在每个源文件的顶部使用这个定义:
#define ASSIGN_FILENUMBER() enum { file_number = __COUNTER__ };
但是,由于每个文件都是单独编译的,这意味着 __COUNTER__ 语句在调用时始终从 0 开始,并且不知道其他文件的存在或它自己的 ID。
另一个考虑因素是编辑 MakeFile(脚本)并在其中添加文件 ID 号。但是,这会将项目构建/功能与我的 IDE 配置紧密联系在一起,这是不可取的。 此外,我不确定我当前的 IDE(Mplab X IDE 或 IAR Embedded Workbench 上的 XC16/XC32 编译器)的可能性。
我想知道是否有任何其他创造性的方法可以让标准 C 预处理器接管任务?
【问题讨论】:
-
您的编译器是否支持预编译头文件?预编译的标头可能会保留
__COUNTER__值,至少这是在 MSVC 文档中编写的。 -
如果您使用 O(1) 算法动态生成唯一 ID 会很好吗?还是我没有得到问题:o
-
我尝试使用
ASSIGN_FILENUMBER宏手动预编译头文件。我的编译器可能是基于 gcc 的,但并不吹嘘它。我可以看到预编译的头文件被拾取(-H 输出),但是,特定于 proccesor 的定义无法编译:invalid attribute space, __sfr__, __unsafe__, etc. ignored。由于用 C 编写的嵌入式软件是完整的静态程序,因此在设备内部动态分配/计算 ID 是没有意义的。此外,跟踪主机会更困难。 -
由于 C 预处理器不知道要编译多少文件来生成您的程序,我认为 C 预处理器将很难提供帮助。
-
虽然不是 C 预处理器,但您可以让 makefile 运行一个 shell/python/perl 脚本,该脚本会在构建代码之前重新生成列表和常量。但更常见的选择是只转储代码地址(可能还有版本或构建纪元时间),并使用引用映射文件或类似工具链调试输出的工具将其转换回开发机器上的文件/源(您需要保留,但实际上不需要加载到目标系统上)。
标签: c embedded c-preprocessor