C 预处理器宏替换#if #else 语句

C preprocessor macro replacing #if #else statements

我现在正在使用此语句在 C 代码中的小错误消息和更广泛的错误消息之间切换:

#ifdef COMPACTC
  error_code ((uint16_t) init_cascade, 5);
#else
  error_message (__func__, "cascades malloc failed");
#endif

(它是嵌入式 C 代码库的一部分,所以我经常没有足够的内存来存储错误消息字符串)。

在第一种情况下(COMPACTC 定义)我只输出函数地址和错误号。在第二种情况下,我输出了完整的函数名称和一条人类可读的错误消息。

由于我现在在整个代码中都复制了这个片段,我希望我可以用一个宏替换它,我可以像这样使用它:

error (init_cascade, "cascades malloc failed", 5)

并根据是否定义了 COMPACTC 提供正确的 C 代码。

也许甚至可以从当前位置自动派生当前函数(或某些唯一标识符),但我认为预处理器不知道它当前在哪个函数的范围内。

另一个改进是,如果可以从错误消息(如哈希值或其他内容)中自动生成唯一的错误代码(在本例中为 5,它基于 return 值)。

那么调用宏就可以这么简单:

error ("cascades malloc failed")

当然,在使用散列时,我需要对其原始消息进行某种引用 (file/comment)。

上下文:AVR 8 位 MCU 上的错误消息

关于这个问题的上下文:此代码是为 ATmega168(只有 2k RAM)编写的,据我所知,Linux 没有可用的 good/recent 模拟器。所以我试图找到一种产生错误 messages/codes 的好方法,而不用让字符串占用我所有的内存。

备选方案:C 函数?

一个完全不同的,可能更灵活的解决方案是定义一个 C 函数 error (function, message, code) 并将 #if/#else/#endif 构造移动到它的主体。 我不确定如果在函数调用中引用字符串文字但从未在函数体内使用过,它是否由 gcc 编译。

编辑:我刚刚测试了这个想法:在调用中使用字符串文字但不在正文中使用它仍然通过 gcc 添加到可执行文件中,所以这个 "alternative" 似乎不起作用。

这实际上应该相当简单:

#ifdef COMPACTC
#   define COMBINED_ERROR(function, message, size) error_code((uint16_t)function, size)
#else
#   define COMBINED_ERROR(function, message, size) error_message (__func__, message)
#endif

现在你可以写:

COMBINED_ERROR(init_cascade, "cascades malloc failed", 5);

对于第一部分我建议:

#ifdef COMPACTC
#   define error(par1, ...) error_code((uint16_t)par1, __VA_ARGS__)
#else
#   define error(par1, ...) error_message (__func__, par1, __VA_ARGS__)
#endif

使用此解决方案,您可以定义任意数量的参数。
对于第二个需求考虑使用宏来插入特定的代码。考虑以下宏:

#define CallWithError(fnc, ...) { \
                                  int RetCode = fnc(__VA_ARGS__);  \
                                  if (RetCode)  \
                                      error(init_cascade, "cascades malloc failed", RetCode);  \
                                }

此时可以使用宏调用函数foo自动生成错误:

CallWithError(foo, 1, "hello");

这将扩展到:

{
    int RetCode = foo(1, "hello");
    if (RetCode)
        error(init_cascade, "cascades malloc failed", RetCode);
}