在我的应用程序中,我有一个用于伪单元测试的构建配置(这是一种手动调试专用功能)。
在这些单元测试中,我想在其翻译单元中访问声明为static
的函数。
是否有GCC选项允许我从任何地方拨打static
个功能?
我想避免:
#if UNIT_TEST_MODE
void myfunction(void)
#else
static void myfunction(void)
#end
{
// body
}
到处!
感谢您的帮助:)。
答案 0 :(得分:4)
不需要冗长。为每个静态函数使用前缀define:
#if UNIT_TEST_MODE
#define UNIT_TEST_STATIC
#else
#define UNIT_TEST_STATIC static
#end
UNIT_TEST_STATIC void myfunction(void)
{
// body
}
另一种选择是将所有静态函数从该.c文件移动到单独的标头。该标头仅包含在该.c文件中,但如果需要,它可以包含在单元测试.c文件中。除非手动包含标题,否则这些功能在其他文件中将保持不可见 (它们必须被定义为静态内联。)
答案 1 :(得分:2)
应用于函数或文件范围变量时,static
关键字表示声明的函数或对象具有内部链接。这意味着只能从同一翻译单元中直接引用这样的函数或对象。海湾合作委员会没有选择改变C语言的核心条款,也不应该改变。
那么,您的替代方案要么
为有问题的函数提供外部联系而不是内部联系,可能是有条件的,或者
通过间接机制使测试代码可用,例如函数指针初始化并由翻译单元内的某个工具(另一个函数,全局变量)提供给测试代码。
第一种选择更简单,但使用它意味着被测代码并不完全等同于为普通用途构建的代码。此外,如果任何以前静态函数的名称与其他全局对象的名称冲突,则此选项不可行。此选项已在其他答案中得到充分论证,因此我不会在此处进一步详细说明。
第二种选择的优点和缺点或多或少是第一种选择的镜像。它更复杂,但是可以使用它们在生成构建中使用的相同形式测试函数,并且可以避免此路由发生名称冲突。这种方法有许多可能的变化;这是一个:
#ifndef TEST_HEADER_H
#define TEST_HEADER_H
struct test_pointers {
int (*function_to_test)(const char *);
};
void initialize_test_pointers(struct test_pointers *pointers);
#endif
static int function_to_test(const char *);
#ifdef ENABLE_TESTING
#include "test_header.h"
extern void initialize_test_pointers(struct test_pointers *pointers) {
pointers->function_to_test = function_to_test;
}
#endif
static int function_to_test(const char *s) {
// ... whatever
}
#include "test_header.h"
int test_it(void) {
struct test_pointers pointers;
char test_input[] = "test THIS!";
const int expected_result = 42;
int result;
initialize_test_pointers(&pointers);
result = pointers.function_to_test(test_input);
return result == expected_result;
}
答案 2 :(得分:0)
不,它不能。此关键字指定函数的可见性,仅作为翻译单元,由launguage标准定义。编译器忽略它会使它不符合。
UPD。要解决您的问题,您确实可以执行预处理程序指令技巧,如您对问题的评论中所述。
答案 3 :(得分:0)
这不能解答您关于GCC的问题,但作为单元测试问题的解决方案,您可以在同一模块中有条件地编译包装函数,
static void myfunction(void)
{
// body
}
#if UNIT_TEST_MODE
void myfunction_test(void)
{
myfunction();
}
#endif
或者,您可以从单元测试包装文件中#include
模块
// unit_test.c
#include "myfunction.c"
void unit_test()
{
myfunction();
}