这个问题是关于gcc构造函数,编译和编译的。链接是对的,但它没有运行。
有一个c:
UTEST_BEGIN()
UID(a_test)
{
printf("a test");
return true;
}
UTEST_END(a)
b.c是simlar:
UTEST_BEGIN()
UID(b_test)
{
printf("b test");
return true;
}
UTEST_END(b)
代码对象使用UID()链接一些测试函数。我的第一个版本添加了UTEST_BEGIN()UTEST_END()以包含UID(),最后我意识到UTEST_BGIN()UTEST_END()是不必要的,当我更改它们时会得到无法预测的结果。
当我更改UTEST_BEGIN(),UID(),UTEST_END()的定义时,我得到了不同的结果。
基本想法来自can-i-auto-collect-a-list-of-function-by-c-macro!
测试1:
#define UTEST_BEGIN() \
static const bool __m_en = true; \
static struct __uti *__m_uti_head = NULL;
bool utest_item_list_add_global(struct __uti *uti);
#define UID(f) \
static bool __uti_##f(void); \
__attribute__((constructor)) \
static void uti_construct_##f(void) \
{ \
printf("%s\n", #f); \
static struct __uti __m_uti_##f = {NULL, this_file_id, __uti_##f, #f }; \
utest_item_list_add_global(&__m_uti_##f); \
} \
static bool __uti_##f(void)
bool unit_test_item_pump_do(int file_id, bool (*f)(void), const char *f_name);
#define UTEST_END(file_name) \
bool unit_test_##file_name(void) \
{ \
if (!__m_en) \
return true; \
struct __uti *cur; \
for(cur = __m_uti_head; cur; cur = cur->next) { \
unit_test_set_run_last_line(__LINE__); \
if (!unit_test_item_pump_do(this_file_id, cur->f, cur->f_name)) \
return false; \
} \
return true; \
}
我得到了正确的结果。我可以通过链接调用__uti_a_test()和__uti_b_test()。实际上,__ uti_xxx()链接与__m_uti_head没有关联,因此我想删除UTEST_BEGIN()& UTEST_END()。
运行gcc -E a.c,宏扩展为:
static const bool __m_en = 1;
static struct __uti *__m_uti_head = ((void *)0);
static bool __uti_a_test(void);
__attribute__((constructor))
static void uti_construct_a_test(void)
{
static struct __uti __m_uti_a_test = {((void *)0), file_id_a, __uti_a_test, "a_test" };
utest_item_list_add_global(&__m_uti_a_test);
}
static bool __uti_a_test(void)
{
printf("a test");
return 1;
}
bool unit_test_a(void)
{
if (!__m_en)
return 1;
struct __uti *cur;
for(cur = __m_uti_head; cur; cur = cur->next) {
unit_test_set_run_last_line(19);
if (!unit_test_item_pump_do(file_id_a, cur->f, cur->f_name))
return 0;
}
return 1;
}
测试2:
#define UTEST_BEGIN()
bool utest_item_list_add_global(struct __uti *uti);
#define UID(f) \
static bool __uti_##f(void); \
__attribute__((constructor)) \
static void uti_construct_##f(void) \
{ \
printf("%s\n", #f); \
static struct __uti __m_uti_##f = {NULL, this_file_id, __uti_##f, #f }; \
utest_item_list_add_global(&__m_uti_##f); \
} \
static bool __uti_##f(void)
#define UTEST_END(file_name)
UID()的定义与Test 1相同。我保留UTEST_BEGIN()& UTEST_END()为空白。编译&链接是对的,但是uti_construct_a_test()& uti_construct_b_test()不执行。
运行gcc -E a.c,宏扩展为:
static bool __uti_a_test(void);
__attribute__((constructor))
static void uti_construct_a_test(void)
{
static struct __uti __m_uti_a_test = {((void *)0), file_id_a, __uti_a_test, "a_test" };
utest_item_list_add_global(&__m_uti_a_test);
}
static bool __uti_a_test(void)
{
printf("a test");
return 1;
}
utest_item_list_add_global()存在于其他.c文件中,该函数将一个节点添加到一个链接中:
static struct __uti *m_uti_head = NULL;
bool utest_item_list_add_global(struct __uti *uti)
{
if (NULL == m_uti_head) {
m_uti_head = uti;
return true;
}
struct __uti *tail = m_uti_head;
while (NULL != tail->next)
tail = tail->next;
tail->next = uti;
return true;
}
扩展的macor似乎是正确的。我认为问题是在链接阶段,我是对的吗?
答案 0 :(得分:3)
我发现gcc 属性((构造函数))具有以下事实:
cons.c是一个包含构造函数的文件。
cons.c:
#include <stdio.h>
static void __attribute__((constructor)) construct_fun(void)
{
printf("this is a constructor\n");
}
void cons(void)
{
printf("this is cons\n");
}
测试1:
main.c中:
#include <stdio.h>
int main(void)
{
printf("this is main\n");
}
编译:
gcc -c cons.c
ar cqs libcon.a cons.o
gcc main.c libcon.a
输出是: 这是主要的
测试2:
main.c中:
#include <stdio.h>
extern void cons(void);
int main(void)
{
cons();
printf("this is main\n");
}
编译:
gcc -c cons.c
ar cqs libcon.a cons.o
gcc main.c libcon.a
输出:
this is a constructor
this is cons
this is main
测试3:
的main.c
#include <stdio.h>
int main(void)
{
printf("this is main\n");
}
编译:
gcc main.c cons.c
输出:
this is a constructor
this is main
运行“gcc -v”,输出:
使用内置规格。 COLLECT_GCC = GCC COLLECT_LTO_WRAPPER =的/ usr /的libexec / GCC / i686的-红帽-LINUX / 4.7.2 / LTO-包装 目标:i686-redhat-linux 配置为:../ configure --prefix = / usr --mandir = / usr / share / man --infodir = / usr / share / info --with-bugurl = http://bugzilla.redhat.com/bugzilla --enable-bootstrap - -enable-shared --enable-threads = posix --enable-checking = release --disable-build-with-cxx --disable-build-poststage1-with-cxx --with-system-zlib --enable -__ cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style = gnu --enable-languages = c,c ++,objc,obj- c ++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --enable-java-awt = gtk --disable-dssi --with-java-home = / usr / lib / jvm / java-1.5.0-gcj-1.5.0.0 / jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar = / usr / share / java / eclipse-ecj。 jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune = generic --with-arch = i686 --build = i686-redhat-linux 线程模型:posix gcc版本4.7.2 20121109(Red Hat 4.7.2-8)(GCC)
我的问题是:
只有构造函数存在于.c文件中,将其编译为静态库,为什么gcc会忽略该构造?如何避免呢?