我有一个带有main()
功能的翻译单元和另一个没有主要功能的TU。假设我只控制第二个而不能触及第一个。
现在,由于我不会进入的原因,我希望能够在main()
运行之前运行一些代码。我知道这可以通过函数调用初始化一个全局变量来完成,但我想隐藏它 - 尽可能少使用宏(我敢说不使用宏?可能不可能,C ++中没有适当的静态块) )
这样做会有什么优雅,或者我们说,不是非常丑陋的方式?更清楚的是,我正在寻找能够多次使用此功能的东西,而不仅仅是让它能够工作一次。我希望它尽可能接近:
// ... at global scope ...
static {
// my code here
}
PS:这个问题与this question about initializing static class members有关,但不一样。这也是出于明确反驳this claim it can't be done in C++的愿望。
注意:是的,我知道静态初始化命令惨败,不需要提醒我...而且我不是要求绕过它的东西。显然,静态运行代码需要谨慎。
答案 0 :(得分:4)
请欣赏static initialization order fiasco:
int f(/* whatever args you want*/)
{
// code to be ran before main()
return 42;
}
static int _ignore = f(/*...*/);
请注意,有时可能不会调用代码,如果没有在其他地方使用(别名"优化了")。其中一种情况是将TU编译成静态库(然后未使用的变量和代码可能不会被拉入可执行文件)。 (E. Maskovsky的注释)。
答案 1 :(得分:2)
这是迄今为止我能想到的最好的。它有效,但实现有点难看。
如果你写:
STATIC_BLOCK {
std::cout << "Hello static block world!" << std::endl;
}
此代码将在main()
之前运行。但请注意,在std::cout
开始之前写入main()
实际上并不是一个好主意。
注意:
静态块实现涉及虚拟变量。为了确保我们不与其他虚拟变量(例如来自另一个静态块 - 或其他任何地方)发生冲突,我们需要一些宏机制。
#define CONCATENATE(s1, s2) s1##s2
#define EXPAND_THEN_CONCATENATE(s1, s2) CONCATENATE(s1, s2)
#define STATIC_BLOCK_IMPL2(function_name,var_name) \
static void function_name(); \
static int var_name __attribute((unused)) = (function_name(), 0) ; \
static void function_name()
#define STATIC_BLOCK_IMPL1(prefix) \
STATIC_BLOCK_IMPL2(CONCATENATE_FOR_STATIC_BLOCK(prefix,_fn),CONCATENATE_FOR_STATIC_BLOCK(prefix,_var))
#define STATIC_BLOCK STATIC_BLOCK_IMPL1(EXPAND_THEN_CONCATENATE(static_block_,__COUNTER__))
备注:强>
__COUNTER__
(因为它是标准的扩展,而不是标准的一部分) - 您可以使用__LINE__
,它也可以。 GCC和Clang支持__COUNTER__
。__attribute__((unused))
是另一个编译器扩展,虽然属性已经进入该语言;例如,请参阅this discussion。如果放弃它,你会收到警告。 最初的灵感来自Andrei Alexandrescu的SCOPE_EXIT
trick。