14

我使用静态全局变量构造函数来方便地注册函数,这个想法是这样的:

typedef int (*FuncPtr)(int);

struct RegHelper
{
    RegHelper(const char * Name, FuncPtr Func)
    {
        Register(Name, Func);
    }
}

#define REGISTER(func) RegHelper gRegHelper_ ## func (#func, func);

现在我可以通过这种方式注册函数(我用它来实现某种反射):

int Foo(int a)
{
    return a * 123;
}

REGISTER(Foo)

int Bar(int a)
{
    return a * 456;
}

REGISTER(Bar)

问题是,如果我在静态库中使用它,有时链接器会检测到编译单元没有被使用,它会丢弃整个东西。所以没有构造全局变量,也没有注册函数……

我的问题是:我能做些什么来解决这个问题?在初始化期间在每个编译单元中调用虚拟函数似乎会触发全局变量的构造,但这感觉不是很安全。还有什么建议吗?

4

6 回答 6

4

要解决这个问题:

  • Visual Studio(在同一解决方案中):链接器>常规>使用库依赖输入=是
  • Gcc:直接与 .o 文件链接

我还没有找到我真正喜欢的解决方案。

于 2009-04-30T11:55:31.070 回答
3

在此处查看答案:强制视觉工作室链接 lib 文件中的所有符号

这个实际上对我有用。其他建议没有。

于 2013-07-31T15:28:26.113 回答
1

查看“构建每种类型数据列表的最佳方法”的答案

其中有两个关键的重要概念。第一的:

(void) register_object;  

使用该对象来确保链接器不会剥离它,并且,

template<typename D> typename automatic_register<D>::exec_register 
    automatic_register<D>::register_object;

确保为每个实例分配一个静态全局变量。您应该将数据保存在此对象中。它有点不同,因为它是每个对象而不是每个类,但是如果你调整你的宏来创建

// Global list of objectsh
struct FpList
{
   FpList( FuncPtr func ) :
      func(func)
   {
      head = next;
      next = this
   }
   FpList* next;
   FuncPtr func;

   static FpList* head;
};
// In .cxx:
FpList* FpList::head = 0;  

然后修改您的注册宏,以便 REGISTER(Foo),以便它创建:

struct register_Foo : FpList
{
   register_Foo( FuncPtr fn ): FpList(fn)
   {
      (void) register_object;  
   }
   static register_Foo register_object;
};

我认为这还不够。您仍然需要实例化模板,传递 if &Foo 并确保

register_Foo register_Foo::register_object

实例是在某处创建的。automatic_register 的模板代码显示了如何在标题中执行此操作。如果您可以将宏放在 .cxx 中,只需声明:

register_Foo register_Foo::register_object( &Foo );

作为宏的一部分。我认为它可能会奏效。(全凭记忆,谁知道呢)。

于 2009-04-30T15:23:42.163 回答
1

如果您在 UNIX 环境中调用带有 whole-archive 选项的 ld 将强制所有对象文件包含在静态库中,无论使用如何。

于 2009-04-30T20:37:09.867 回答
1

是的,我也遇到过这个问题。我发现的唯一可靠的方法是:

  • 将库变成 DLL

或者:

  • 将注册对象移动到可执行文件中

这些都不是完美的,尽管如果你不介意使用 DLLS,DLL 解决方案是可以的,我也很想听听其他解决方案。

于 2009-04-30T10:50:24.847 回答
1

同一问题的另一种可能的解决方案。通过函数调用获取常量值。像这样:

常数.h

const char blah[10];

extern const char *get_blah();

常数.c

#include "header.h"

const char *get_blah()
{ return blah; }

这帮助我做到了!

于 2015-08-26T11:22:13.963 回答