gpt4 book ai didi

c++ - 使用 init_seg 时如何为三个 C++ 对象命名部分/组?

转载 作者:行者123 更新时间:2023-11-27 23:55:29 25 4
gpt4 key购买 nike

我正在使用 init_seg 来控制三个 C++ 类对象的创建。每个对象都在不同的源文件/翻译单元中。调试显示在 CRT 初始化期间正在按预期创建对象。

对象正在按照其源文件的字母顺序进行初始化。我想更改它,因为它不太正确。我在 init_seg 上访问了 MSDN 的页面, 并说明用途是:

#pragma init_seg({ compiler | lib | user | "section-name" [, func-name]} )

看来 libsection-name 的使用是互斥的,所以我不清楚如何使用 init_seg(lib) 并提供部分/组名称以获得正确的字母顺序。

当我尝试使用按字母顺序排列的字符串来控制顺序时:

#pragma init_seg(lib, "01")

它会导致警告,我猜这意味着事情不会按预期工作:

warning C4081: expected ')'; found ','

当我尝试直接使用 ".CRT$XCB"".CRT$001"".CRT 直接插入 CRT 启动代码时$XCB001"(以及其他使用字母顺序的变体):

#pragma init_seg(".CRT$XCB")

它会导致另一个警告,我猜这意味着事情不会按预期工作:

warning C4075: initializers put in unrecognized initialization area

我在 Stack Overflow 上发现了一个关于它的问题,但是 answer was a guess并且它不涵盖多个翻译单元。我还找到了 KB104248 的存档在 Wayback Machine 上,但它也没有太大帮助,因为它只显示了 compilerlibuser 的使用。

所以我的问题是,如何利用 init_seg 来控制三个不同源文件中三个对象的精确创建顺序?

最佳答案

以下是我在 XP 和 VS2002/VS2003、Vista 和 VS2005/VS2008、Windows 7 和 VS2008/VS2010、Windows 8 和 VS2010/VS2012/VS2013 以及使用 VS2015 的 Windows 10 上进行测试后发现的结果。 #pragma_init(<name>)从 VC++ 1.0 天开始就可用。 MS 没有发布太多关于它的信息,但我们知道它来自 VC++1.0 (archived KB104248) 的文档。通过VS2017 .

  1. #pragma init_seg(lib)几乎是完美的。但是,对象文件在 VS2008 及更早版本中按字母顺序排列,因此初始化顺序为 a-b-c (不需要的)而不是 c-b-a (期望)。它在 VS2010 及更高版本上没问题。不明显的是订单的布局恰好为 c-b-avcproj文件。

  2. #pragma init_seg(".CRT$XCB-0NN")似乎工作。我们的std::strings STRING_ASTRING_B很早就创建了(并且对象的顺序正确),但是 STRING_B导致 suhutdown 崩溃。地址是0x0000000d , 它出现了 std::string (及其 vtable)过早销毁。

  3. #pragma init_seg(".CRT$XCU-0NN")在启动和关闭期间按预期工作。如果我正确解析了我阅读的内容,那么 U在组名XCU指示用户定义的对象。这意味着我们的对象是在 #pragma init_seg(lib) 之间的某处创建的和 #pragma init_seg(user)提供。

下面是如何从源文件中初始化一个对象 C,然后是一个对象 B,然后是一个对象 A a.cpp , b.cppc.cpp .

源文件 a.cpp :

class A
{
...
};

#pragma warning(disable: 4075)
#pragma init_seg(".CRT$XCU-030")
A a; // created 3rd
#pragma warning(default: 4075)

源文件 b.cpp :

class B
{
...
};

#pragma warning(disable: 4075)
#pragma init_seg(".CRT$XCU-020")
const B b; // created 2nd
#pragma warning(default: 4075)

源文件 c.cpp :

#pragma warning(disable: 4075)
#pragma init_seg(".CRT$XCU-010")
const std::string c; // created 1st
const std::string d; // created 1st
#pragma warning(default: 4075)

我们的用例是创建三个只读对象并避免 C++ 的 static initialization order fiasco 问题。和微软的 thread local storage .

该技术避免了在 C++03 中缺少 C++ 动态初始化程序。它还解决了微软无法提供 C++11 的 Dynamic Initialization and Destruction with Concurrency 的问题。 (或者更准确地说,微软 10 年来未能提供核心语言功能)。

这里是对 Thread Local Storage (TLS) 问题的引用在 MSDN 上:

On Windows operating systems before Windows Vista, __declspec( thread ) has some limitations. If a DLL declares any data or object as __declspec( thread ), it can cause a protection fault if dynamically loaded. After the DLL is loaded with LoadLibrary, it causes system failure whenever the code references the __declspec( thread ) data. Because the global variable space for a thread is allocated at run time, the size of this space is based on a calculation of the requirements of the application plus the requirements of all the DLLs that are statically linked. When you use LoadLibrary, you cannot extend this space to allow for the thread local variables declared with __declspec( thread ). Use the TLS APIs, such as TlsAlloc, in your DLL to allocate TLS if the DLL might be loaded with LoadLibrary.

还值得一提的是,似乎对部分或组名称中的字符数有限制。存档KB 104248使用名称 "user_defined_segment_name" 26 个字符。

关于c++ - 使用 init_seg 时如何为三个 C++ 对象命名部分/组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42895755/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com