GCC构造函数不执行

时间:2013-04-18 08:08:09

标签: c gcc

这个问题是关于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似乎是正确的。我认为问题是在链接阶段,我是对的吗?

1 个答案:

答案 0 :(得分:3)

我发现gcc 属性((构造函数))具有以下事实:

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

  1. 如果cons.c文件中只存在构造函数,则将其编译为静态库,然后将其与main()链接,构造函数将被忽略。
  2. 如果cons.c中存在main.c中调用的任何函数,则将cons.c编译为静态库,然后将其与main()链接,将在main之前调用构造函数。
  3. 如果使用“gcc main.c cons.c”,将在main之前调用构造函数。
  4. 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会忽略该构造?如何避免呢?