首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >GCC构造函数未执行

GCC构造函数未执行
EN

Stack Overflow用户
提问于 2013-04-18 16:08:09
回答 1查看 1.5K关注 0票数 3

这个问题是关于gcc的构造函数,编译和链接是正确的,但是它不能运行。

有一个a.c:

代码语言:javascript
复制
UTEST_BEGIN()
UID(a_test)
{
    printf("a test");
    return true;
}
UTEST_END(a)

b.c是类似的:

代码语言:javascript
复制
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:

代码语言:javascript
复制
#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,宏扩展为:

代码语言:javascript
复制
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:

代码语言:javascript
复制
#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()的定义与测试1相同。我将UTEST_BEGIN() & UTEST_END()保留为空。编译和链接是正确的,但是uti_construct_a_test()和uti_construct_b_test()没有执行。

运行gcc -E a.c,宏扩展为:

代码语言:javascript
复制
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文件中,该函数将一个节点添加到链接中:

代码语言:javascript
复制
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似乎也是对的。我认为问题是在链接阶段,我说的对吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-04-23 13:56:41

我发现gcc attribute((constructor))有以下事实:

Cont.c是一个包含构造函数的文件。

  1. 如果Con.c文件中只有构造函数,将其编译为静态库,然后用main()链接,则忽略构造函数。
  2. 如果Con.c中存在调用main.c的函数,将Con.c编译为静态库,然后用main()链接,构造函数将在main()之前调用。
  3. 如果使用"gcc main.c Con.c“,则会在main之前调用构造函数。

cons.c:

代码语言:javascript
复制
#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:

代码语言:javascript
复制
#include <stdio.h>
int main(void)
{
        printf("this is main\n");
}

编译方式:

代码语言:javascript
复制
gcc -c cons.c
ar cqs libcon.a cons.o
gcc main.c libcon.a

输出为: this is main

测试2:

main.c:

代码语言:javascript
复制
#include <stdio.h>
extern void cons(void);
int main(void)
{
        cons();
        printf("this is main\n");
}

编译方式:

代码语言:javascript
复制
gcc -c cons.c
ar cqs libcon.a cons.o
gcc main.c libcon.a

输出:

代码语言:javascript
复制
this is a constructor
this is cons
this is main

测试3:

main.c

代码语言:javascript
复制
#include <stdio.h>
int main(void)
{
        printf("this is main\n");
}

编译方式:

代码语言:javascript
复制
gcc main.c cons.c

输出:

代码语言:javascript
复制
this is a constructor
this is main

运行"gcc -v",输出:

使用内置规范。COLLECT_LTO_WRAPPER=/usr/libexec/gcc/i686-redhat-linux/4.7.2/lto-wrapper目标: 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-with-cxx--disable-build-POSTAGE1 --with-system-zlib --启用-__cxa_atexit--禁用-libunwind-异常--启用-gnu-唯一对象--启用-链接器-构建-id--使用链接器-散列样式=gnu--启用-语言=c,c++、objc、obj-c++、java、fortran、ada、go、lto --enable-插件--enable-initfini-array --enable-java-awt=gtk --dssi --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile -enable-java-multifile mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable multilib-with-ppl --with-cloog -with-tune=generic --with-arch=i686--build=i686-redhat-linux线程模型:POSIX4.7.2- 20121109 (Red Hat 4.7.2-8) ( gcc )

我的问题是:

.c文件中只有构造函数,编译成静态库,为什么gcc会忽略这个构造函数?如何避免呢?

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16085992

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档