0

(环境:gcc 4.6、c++11、glibc 2.13、binutils 2.21)

请考虑以下“链接”演示作为背景:

foo.h

#pragma once
#include <iostream>

void foo();

foo1.cpp

#include "foo.h"

void foo()
{
    std::cout << "foo1";
}

foo2.cpp

#include "foo.h"

void foo()
{
    std::cout << "foo2";
}

主.cpp

#include "foo.h"

int main()
{
    foo();
}

生成文件

compile: main.o foo1.o foo2.o

case1: compile
    g++ -o case1.x main.o

case2: compile
    g++ -o case2.x main.o foo1.cpp

case3: compile
    g++ -o case3.x main.o foo1.o foo2.o

clean:
    rm *.o *.x

我们有一个函数声明如下:

void foo();

我们对它有多个定义,一个在 foo1.cpp 中,一个在 foo2.cpp 中。

我们将 .cpp 文件编译成 .o 文件:

$ make compile

没问题,main.o、foo1.o 和 foo2.o 都生成了。

情况1

然后我们尝试链接 main.o:

$ make case1
error: undefined reference to 'foo()'

好的,main.o 引用了 foo 但没有链接定义。

案例2

现在我们尝试链接 main.o 和 foo1.o

$ make case2

在 foo1.o 中有一个 foo 的定义,所以它链接没有错误。

案例3

现在我们尝试链接 main.o foo1.o 和 foo2.o

$ make case3
error: multiple definition of 'foo()'

链接器在 foo1.o 和 foo2.o 中找到了 foo 的两个定义,因此它不是随机选择一个,而是快速失败并出现错误并且不链接。

问题

我的问题是:

  1. 是否可以将 foo1.cpp 的 foo 版本(可能带有某种 gcc 属性或编译指示)的定义标记为“弱”?具体意味着我希望案例 1 和案例 2 的行为保持不变,而案例 3 的行为更改为成功链接而没有警告或错误,并且 foo2.cpp 中的 foo 定义被链接(覆盖“弱”定义在 foo1.cpp 中)。

  2. 是否可以在运行时测试(并分配给布尔变量)是否链接了弱版本的 foo 或强版本(显然不执行函数)。即在main中实现一个函数,如下所示。

    template<typename FunctionPtr>
    bool is_weak_linked(FunctionPtr fp);
    

is_weak_linked(foo) 应该在案例 2 中返回 true,在案例 3 中返回 false。

4

1 回答 1

1

到#1:

void foo() __attribute__((weak));
void foo()
{
    ...
}

到#2:我不相信,不是你正在做的静态链接。该信息在链接时丢失。

编辑

你总是可以围绕#2抽象你的方式。一些例子:

// Foo.h
extern void foo();
extern "C" void default_foo();
extern const bool is_weak_foo_linked;
template <void (*)()> bool is_weak_linked();

// Foo1.cc
extern "C" void default_foo() {...}
void foo() __attribute__((weak, alias("default_foo")));

extern const bool __attribute__((weak)) is_weak_foo_linked=true;
template <> bool is_weak_linked<foo>() __attribute__((weak));
template <> bool is_weak_linked<foo>() {return true;}

// Foo2.cc
void foo() {...}
extern const bool is_weak_foo_linked=false;
template <> bool is_weak_linked<foo>() {return false;}

// main.cc
#include "foo.h"
#include <iostream>
int main() {
    foo();
    std::cout<<is_weak_foo_linked<<std::endl;
    std::cout<<is_weak_linked<foo>()<<std::endl;
    std::cout<<(foo==default_foo)<<std::endl;
}
于 2012-02-01T23:30:47.163 回答