混合 STL 调试/发布库
Posted
技术标签:
【中文标题】混合 STL 调试/发布库【英文标题】:Mixing STL debug/release libraries 【发布时间】:2015-08-04 13:27:21 【问题描述】:我知道,将相互传递 STL 容器的调试库和发布库混合使用会导致大问题。但是“调试”或“发布”中究竟是什么导致了这种情况?
我有一个构建为“发布”的 QT 项目,但它在编译器标志中添加了 /DEBUG。 如果我在“调试”(也有 /DEBUG 标志)下构建另一个 QT 项目,它们是否兼容?
或者是否有优化标志或其他标志使它们不兼容?
基本上,有没有一种方法可以让我查看 2 个库的编译行并看到“不要混合这些!”的内容?
【问题讨论】:
【参考方案1】:这是未定义的行为,因此它可能会起作用,但更有可能会使您的应用崩溃。它还取决于 stl 实现,在调试版本中,它可能会启用额外的检查并分配额外的内存,从而使数据布局在发布模式下有所不同。最后,这违反了 ODR 规则(一个定义规则),再次导致未定义的行为。
我有一个构建为“发布”的 QT 项目,但它在编译器标志中添加了 /DEBUG。如果我在“调试”(也有 /DEBUG 标志)下构建另一个 QT 项目,它们是否兼容?
如果您的 Release 包含与 Debug 完全相同的编译器标志,那么我会说它们是兼容的。
或者是否有优化标志或其他标志使它们不兼容?
你应该能够看到那些标志,我不认为优化标志应该导致 UB 问题,它在编译阶段使用的完全不同的宏会导致 ODR 违规。也许有一些优化标志会改变结构中的对齐方式......
基本上,有没有一种方法可以让我查看 2 个库的编译行并看到“不要混合这些!”的内容?
这里不知道。
为什么您首先要混合不同的构建库?这是自找麻烦。
【讨论】:
我不是故意混合它们。我在将向量从一个库传递到另一个库时遇到问题,我很确定这是调试/发布的事情。但我尝试在进行更改之前准确了解发生了什么,我希望 100% 确定而不是假设,因为重建使问题消失了。 可能链接了错误的 STL 库?是什么告诉编译器在调试 STL 库和发布库中进行链接? 在 VS 中,您可以在 Build -> Configuration Manager 中检查编译了哪些项目构建。配置表的每一行的配置列应该相同。【参考方案2】:不是真的。关于 Visual C++ 的 STL 实现,容器的数据成员对应于迭代器检查,只有在设置了一些预处理器变量时才会编译。这些变量是基于 NDEBUG 预处理器变量的默认值,该变量是“无调试”的准标准。但这些也可以直接从命令行、头文件或 Visual Studio 属性页等设置。
例如:所有容器都派生自_Container_base
,而这是一个依赖于_ITERATOR_DEBUG_LEVEL
的类型定义。不同的_Container_base
实现具有不同的内存布局,这就是导致调试版本和发布版本不兼容的原因。
/DEBUG 编译器标志告诉编译器是否生成调试信息,并且还可能影响优化设置的默认值,但我不确定这一点,当然这取决于编译器。
就像可能有一个不依赖于任何预处理器指令的 STL 实现一样,在这种情况下,无论您如何编译、调试或释放它,内存布局都是相同的,因此可以通过模块之间的编译方式不同。
【讨论】:
有没有办法可以看到每个库中的 _ITERATOR_DEBUG_LEVEL 值? 你知道吗,QT 会根据你运行 qmake release 还是 qmake debug 来设置 ITERATOR_DEBUG_LEVEL 吗? 我假设 Qt 本身不使用 Visual C++ 的 STL 实现,但有自己的 Qt 风格的容器。不幸的是,我不知道 Qt 是否有迭代器调试模式,但我猜它有。但是它的开启或关闭方式与Visual C++的STL使用的方式肯定不同,所以我认为ITERTAOR_DEBUG_LEVEL预处理宏不会影响Qt。【参考方案3】:首先,/DEBUG
标志实际上并没有创建“调试”版本。它只是告诉链接器生成调试信息并创建一个 .pdb 文件以及生成的二进制文件。
关于调试和发布 MSVC++ 运行时之间的区别,问题在于不同的运行时对于同一个对象可以有不同的大小。例如在调试中,可能会将额外信息放在迭代器中,以确保它们在运行时的有效性。如果代码是针对这些结构的发布版本编译的,那么很可能会损坏。另一个问题是,如果一个对象从一个运行时的堆中分配并试图在另一个运行时的堆上释放。
【讨论】:
以上是关于混合 STL 调试/发布库的主要内容,如果未能解决你的问题,请参考以下文章