嵌套预处理器指令或其他技巧以有条件地重新定义 static 关键字

nesting preprocessor directives or other trickery to conditionally redefine the static keyword

我正在使用 unity 进行单元测试。

我在整个项目中都有一个 header,我将其包含在一些辅助宏中,例如一个断言包装器,我可以使用它来跟踪触发了哪个断言。

在那header我还有如下定义:

#define static //nothing

我从这篇文章中学到了这个小技巧: http://www.embedded.com/design/programming-languages-and-tools/4007177/2/Doing-C-code-unit-testing-on-a-shoestring-Part-1-The-basics-and-the-tools

这使我可以为静态函数编写单元测试,并允许我从我的测试工具中访问任何相关的文件范围数据。

问题是这完全破坏了函数范围内的静态。文章继续说如果我这样做:

#define static extern

然后可以在测试工具中定义函数范围内的任何静态变量。我们要去比赛了,对吧?不完全是。

因为出现以下情况

void foo()
{
    extern bool my_flag = false;
}

现在我们正在为声明提供初始化程序,这是无效的。所以这意味着我以这种方式处理的任何静态变量本质上都需要在启动后进行初始化。

因为函数中的静态变量相对不常见,我想我可以通过定义一个新符号来规避这个问题,LOCAL_STATIC。所以现在在我的header中我有以下

#define static extern
#define LOCAL_STATIC static

但这不起作用,因为这些指令严格按顺序求值 - #define LOCAL_STATIC static 变成 #define LOCAL_STATIC extern,或者至少这似乎是正在发生的事情。因为 LOCAL_STATIC 会产生相同的错误,并且最终会被预处理器更改为 extern。

那么有什么办法解决这个问题吗?

AFAIK 这样的事情是不可能的:

#define LOCAL_STATIC  \
#undef static         \
static                \
#define static extern

我唯一能想到的就是单独留下 static 并定义一个新符号,比如 HARNESS_ACCESSIBLE.

#ifdef UNIT_TEST
#define HARNESS_ACCESSIBLE extern
#else
#define HARNESS_ACCESSIBLE static
#endif

但这会使生产代码变得混乱,因为这个新的奇怪的东西 "HARNESS_ACCESSIBLE"。函数内的静态变量通常很少见,但几乎所有静态函数(除了琐碎的辅助函数)都需要通过我的测试从外部访问 运行ner.

我一直在努力避免在构建之前编写一个必须 运行 的单独脚本,但我现在已经达到了这一点。

我认为您创建 HARNESS_ACCESSIBLE 宏的想法是解决此问题的最简洁方法。您绝对不想因为您描述的原因而#define-ing 离开static

我不认为使用这个宏会使您的代码混乱。您只需将它放在 static 的位置,它让您可以选择准确指定您希望能够对哪些函数进行单元测试并显式保留这些次要实用程序函数 static.