0

我有一个具有我的main()功能的翻译单元和另一个没有 main 的翻译单元。假设即使我只控制第二个而不能触摸第一个。

现在,由于我不会深入讨论的原因,我希望能够在运行之前运行一些代码main()。我知道这可以通过使用函数调用初始化全局变量来完成,但我想隐藏它 - 尽可能少地使用宏(我敢说不使用宏吗?可能是不可能的,C++ 中没有适当的静态块)

什么是优雅的,或者我们应该说,不是很丑陋的方式?更清楚地说,我正在寻找可以提供此功能以供多次使用的东西,而不仅仅是让它工作一次的东西。我希望它尽可能接近:

// ... at global scope ...
static {
    // my code here
}

PS:这个问题与这个关于初始化静态类成员的问题有关,但不一样。它的动机还在于希望清楚地反驳这种说法,它不能在 C++ 中完成

注意:是的,我知道静态初始化顺序惨败,无需提醒我......而且我不是要绕过它的东西。显然,静态运行代码需要一些谨慎。

4

2 回答 2

5

请欣赏静态初始化命令惨败

int f(/* whatever args you want*/)
{
    // code to be ran before main()
    return 42;
}

static int _ignore = f(/*...*/);

请注意,有时代码可能不会被调用,如果没有在其他任何地方使用(别名“优化”)。其中一种情况是当 TU 被编译成静态库时(然后未使用的变量和代码可能不会被拉入可执行文件中)。(E. Maskovsky 的注释)。

于 2015-12-18T16:30:04.060 回答
2

这是迄今为止我能想到的最好的。它有效,但实现有点丑陋。

用法

如果你写:

STATIC_BLOCK {
    std::cout << "Hello static block world!" << std::endl;
}

此代码将在您的main(). 但是,请注意,在开始std::cout之前写入main()实际上并不是一个好主意。

笔记:

  • 必须用花括号将静态块代码括起来(不需要尾随分号;感谢@KlitosKyriacou 的建议)。
  • 如果您不使用花括号,则可能会出现难以理解的错误消息。
  • C++中不保证静态代码的相对执行顺序。

执行

静态块实现涉及一个虚拟变量。为了确保我们不会与其他一些虚拟变量(例如来自另一个静态块 - 或其他任何地方)发生冲突,我们需要一些宏机制。

#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))是另一个编译器扩展,尽管属性已经进入语言;例如,请参阅此讨论。如果你放下它,你会得到一个警告。
  • 代码是 C++98(忽略编译器扩展),即您不需要任何支持的现代 C++ 构造。不幸的是,它不符合 C 的条件(其中初始化程序必须是常量)。

最初灵感来自 Andrei Alexandrescu 的SCOPE_EXIT把戏

于 2015-12-18T16:32:08.747 回答