Reputation: 3470
In my application I have a build config for pseudo unit testing (this is more a kind of manual debugging a dedicated function).
In those unit tests I'd like to access functions declared as static
in their translation unit.
Is there an option of GCC that would allow me to call static
functions from anywhere?
I'd like to avoid:
#if UNIT_TEST_MODE
void myfunction(void)
#else
static void myfunction(void)
#end
{
// body
}
Everywhere!
Thanks for your help :).
Upvotes: 6
Views: 2205
Reputation: 181459
As applied to a function or file-scope variable, the static
keyword means that the declared function or object has internal linkage. That means such a function or object can be directly referenced only from within the same translation unit. GCC has no option to alter this core provision of the C language, nor should it have.
Your alternatives, then, are either
to give the functions in question external linkage instead of internal linkage, perhaps conditionally, or
to make them available to the test code via an indirect mechanism, such as function pointers initialized and provided to the test code by some facility (another function, a global variable) inside the translation unit.
The first alternative is simpler, but using it means that the code under test is not wholly equivalent to code built for ordinary use. Additionally, this option is not viable if the names of any of the erstwhile-static functions collide with the names of other global objects. This option has been adequately demonstrated in other answers, so I won't go into further detail here.
The pros and cons of the second alternative are more or less the mirror image of those of the first. It is more complicated, but the functions can be tested in the same form that they have in the production build, and you can avoid name collisions by this route. There are many possible variations on this approach; here's one:
#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;
}
Upvotes: 4
Reputation: 1690
This does not answer your question about GCC, but as a solution to your unit testing problem, you could conditionally compile a wrapper function in the same module,
static void myfunction(void)
{
// body
}
#if UNIT_TEST_MODE
void myfunction_test(void)
{
myfunction();
}
#endif
Or, you could #include
the module from a unit test wrapper file,
// unit_test.c
#include "myfunction.c"
void unit_test()
{
myfunction();
}
Upvotes: 0
Reputation: 25753
There is not need to be verbose. Use a prefix define for every static function:
#if UNIT_TEST_MODE
#define UNIT_TEST_STATIC
#else
#define UNIT_TEST_STATIC static
#end
UNIT_TEST_STATIC void myfunction(void)
{
// body
}
Another option is to move all static function from that .c file to a separate header. That header is included only in that .c file, but it can be included in the unit test .c file if needed. The functions will remain invisible in other files, unless the header is manually included.
(They will have to be defined as static inline. )
Upvotes: 7
Reputation: 772
No, it can not. This keyword specifies visibility of a function to be translation-unit only, as defined by launguage standard. Ignoring it by a compiler would render it non-conformant.
UPD. To solve your problem, you can indeed do the preprocessor directive trick, as mentioned in comments to your question.
Upvotes: 0