C++习语,用于在任意翻译单元中的main之前执行任意代码
C++ Idiom for executing arbitrary code before main in arbitrary translation unit
我有一个带有main()
函数的翻译单元和另一个没有main的TU。甚至假设我只控制第二个,而不能触摸第一个。
现在,由于我不想深入讨论的原因,我希望能够在main()
运行之前运行一些代码。我知道这可以通过用函数调用初始化全局变量来完成,但我想隐藏这一点——尽可能少地使用宏(我敢说不使用宏吗?可能不可能,C++中没有合适的静态块)
什么是一种优雅的,或者我们可以说,不是很丑陋的方式来做这件事?更明确地说,我正在寻找一种可以多次使用该功能的东西,而不仅仅是一次工作的东西。我希望它接近:
// ... at global scope ...
static {
// my code here
}
PS:这个问题与初始化静态类成员的问题有关,但不相同。它的动机也是希望清楚地反驳这一说法——这在C++中是做不到的。
注意:是的,我知道静态初始化顺序的失败,没有必要提醒我……我并不是在要求绕过它的东西。显然,静态运行代码需要一些谨慎。
请享受静态初始化顺序的惨败:
int f(/* whatever args you want*/)
{
// code to be ran before main()
return 42;
}
static int _ignore = f(/*...*/);
请注意,如果不在其他地方使用,有时可能不会调用代码(别名"optimized-out")。其中一种情况是将TU编译到静态库中(然后可能不会将未使用的变量和代码拉入可执行文件中)。(E.马斯科夫斯基的说明)。
这是迄今为止我能想到的最好的。它是有效的,但实现有点模糊。
用法
如果你写:
STATIC_BLOCK {
std::cout << "Hello static block world!" << std::endl;
}
此代码将在main()
之前运行。然而,请注意,在main()
开始之前写入std::cout
实际上并不是一个好主意。
注意:
- 您必须用大括号将静态块代码括起来(不需要尾随分号;感谢@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的条件(其中初始化项必须是常量)
最初的灵感来自安德烈·亚历山德雷斯库的SCOPE_EXIT
技巧
相关文章:
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 代码在main()中运行,但在函数中出现错误
- 当我在main中声明了我的2d数组时,为什么我的程序会退出
- QML:修改在不同QML文件(而非main.QML)中定义的子对象的属性
- 不确定要在我的main中放入什么才能使我的代码正常工作
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 函数是否可以访问传递给main()的参数
- 在main()之外初始化std::vector会导致性能下降(多线程)
- 从函数返回任意简单类型的数据
- 我的 int main() 中出现堆栈溢出错误
- C++变量名(可以将 main 声明为变量,但对于其他函数名称则不然)
- 当我尝试在 Main 中调用插入函数时,它不是取数字?
- 如何生成一个随机的 n 位数,其中 n 是任意的
- File.cpp.o:OpenPose 标志 CMakeFiles/.. 的多重定义/main.cpp.o:首先在这里定
- 为什么类和 main() 函数中也有动态内存分配
- 在 main.cpp 的上下文中找不到目录(带有 CMake 的快板)
- 我想在 Main 中用 C++ 调用其他类中的一个类,但我做不到
- "main"函数堆栈中的对象在第一个任务运行时被覆盖 (FreeRTOS)
- 为什么 'main' 函数中的局部 int 变量会自动初始化?
- C++习语,用于在任意翻译单元中的main之前执行任意代码