我想知道是否可以在VC中使用C构造函数,就像在GCC中使用它们一样。
使用__attribute__关键字的gcc方法非常简单,不幸的是VC似乎甚至都不知道这个关键字,因为我不是Win32程序员,所以我想知道是否存在某种等效的关键字。
请注意-这是一个C程序,甚至不是C ++或C#(因为用这些语言很容易做到)
对于那些还没有使用过它的人,它有什么作用? (您需要它做什么?)
动态链接器在加载对象时会运行任何标记为constructor的函数。
@:Jalf:属性构造函数的工作原理是什么?
下面的C代码演示了如何定义在main执行之前在程序/库加载时调用的void(void)函数。
对于MSVC,这会将指针指向用户初始化程序部分(.CRT $ XCU)中的函数,与编译器为构造函数调用静态C ++对象所做的基本相同。 对于GCC,使用构造函数属性。
// Initializer/finalizer sample for MSVC and GCC/Clang.
// 2010-2016 Joe Lowe. Released into the public domain.
#include
#include
#ifdef __cplusplus
#define INITIALIZER(f) \
static void f(void); \
struct f##_t_ { f##_t_(void) { f(); } }; static f##_t_ f##_; \
static void f(void)
#elif defined(_MSC_VER)
#pragma section(".CRT$XCU",read)
#define INITIALIZER2_(f,p) \
static void f(void); \
__declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
__pragma(comment(linker,"/include:" p #f"_")) \
static void f(void)
#ifdef _WIN64
#define INITIALIZER(f) INITIALIZER2_(f,"")
#else
#define INITIALIZER(f) INITIALIZER2_(f,"_")
#endif
#else
#define INITIALIZER(f) \
static void f(void) __attribute__((constructor)); \
static void f(void)
#endif
static void finalize(void)
{
printf("finalize
");
}
INITIALIZER( initialize)
{
printf("initialize
");
atexit( finalize);
}
int main( int argc, char** argv)
{
printf("main
");
return 0;
}
嗨乔:很棒的帖子!我真的需要使用VC的技巧。在C(而非C ++)中自动注册单元测试功能至关重要。顺便说一句:宏INITIALIZER的第二行中应该有一个结尾
这样的构造器将在新的Visual Studio版本中进行优化。它是众所周知的,不幸的是尚未解决的错误。到目前为止,我发现的唯一解决方法是:必须禁用项目属性> C / C ++>优化>整个程序优化(/ GL)。
我遇到了与上述相同的问题,因此请不要在上面粘贴复制代码(假设它可以正常工作)。
由于以下原因,GLib最近从使用.CRT$XCU部分切换为使用DllMain:bugzilla.gnome.org/show_bug.cgi?id=752837
@ user3042599。感谢您对MSVC 2015链接时间优化问题的注意。我已经编辑了代码示例,并且应该没有问题,尽管由于使用__pragma(),现在它需要MSVC 2008或更高版本。
嗨,很抱歉,要恢复旧线程...我也遇到同样的问题,该函数是:`void __attribute __((constructor))init(){//设置GPU内存管理cuda :: gpu_mat_allocator = new cuda :: Allocator( ); // cv :: cuda :: GpuMat :: setDefaultAllocator(cuda :: gpu_mat_allocator); }`我将上面的示例用于:`INITIALIZER(initialize){cuda :: gpu_mat_allocator = new cuda :: Allocator(); atexit(完成); }`正确吗?
我认为没有办法避免在MSVC中使用C ++功能。 (MSVC的C支持仍然很糟糕。)
未经测试,但这至少应允许相同的代码在MSVC和GCC中都能工作。
#if defined(_MSC_VER)
struct construct { construct(void (*f)(void)) { f(); } };
#define constructor(fn) \
void fn(void); static constructor constructor_##fn(fn)
#elif defined(__GNUC__)
#define constructor(fn)
void fn(void) __attribute__((constructor))
#endif
static constructor(foo);
void foo() {
...
}
据我所知,这不适用于MSVC 2013或2015上的纯C。似乎C编译器模式不支持结构中的构造函数。我试图使它以各种方式工作。
您可能对DllMain感兴趣。
它必须在输入main()之前执行,多数民众赞成在dll中,这有何关系? :/
人们对__attribute __((constructor))唯一真正的用途是在共享库中使用它们,就像模拟DllMain :)
__attribute__((constructor))即使在单个程序映像中也很有用;例如,在库和系统调用周围插入全局挂钩,或注册内置的"插件",或初始化动态链接的模块在其" DllMain"中均需要的数据结构。
我在MSVC中尝试了最后一个答案
#ifdef _MSC_VER
#pragma section(".CRT$XCU",read)
#define INITIALIZER2_(f,p) \
static void f(void); \
__declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
__pragma(comment(linker,"/include:" p #f"_")) \
static void f(void)
#ifdef _WIN64
#define INITIALIZER(f) INITIALIZER2_(f,"")
#else
#define INITIALIZER(f) INITIALIZER2_(f,"_")
#endif
#else
#define INITIALIZER(f) \
static void f(void) __attribute__((constructor)); \
static void f(void)
#endif
但INITIALIZER(f)不能出现在两个具有相同函数名传递给INITIALIZER的文件中,以下定义将允许
#ifdef _MSC_VER
#define INITIALIZER(f) \
static void f();\
static int __f1(){f();return 0;}\
__pragma(data_seg(".CRT$XIU"))\
static int(*__f2) () = __f1;\
__pragma(data_seg())\
static void f()
#else
#define INITIALIZER(f) \
__attribute__((constructor)) static void f()
#endif
我的答案中的链接器编译指示是必需的,并且确实具有初始化程序函数名称对于整个exe / dll必须唯一的效果。请参阅user3042599在我的示例下的评论以及我的回复。我不知道节名称的更改是否是链接器编译指示的替代解决方案,但是它将带来其他副作用。