【问题标题】:memory address of a member variable of argument objects changes when dll function is called调用 dll 函数时,参数对象的成员变量的内存地址发生变化
【发布时间】:2012-03-01 02:31:56
【问题描述】:

类 SomeClass {
//一些成员
MemberClass one_of_the_mem_; }

我在 dll 中有一个函数 foo( SomeClass *object ),它是从 exe 调用的。

问题

one_of_the_mem_ 的地址在调度 dll 调用期间发生变化。

详情

调用之前(来自 exe):

             '&(this).one_of_the_mem_' - `0x00e913d0`

之后 - 在 dll 本身中:

             '&(this).one_of_the_mem_' - `0x00e913dc`

对象的地址保持不变。只有每次地址偏移c的成员。

我想要一些关于如何解决此问题的指示。

代码:

来自 Exe 的代码

stat = module->init ( 这个, object_a, &object_b, 对象_c, con_dir );

DLL 中的代码

Status_C ModuleClass( SomeClass *object, int index, Config *conf, const char* name)
{
    _ASSERT(0); //DEBUGGING HOOK
    ...

更新 1:

我按照迈克尔的指示比较了成员的偏移量,它们在两种情况下都是相同的。

更新 2:

我找到了一种方法来转储类布局并注意到大小的差异,但我必须弄清楚为什么会发生这种情况。

linked 是我发现转储类布局的问题。

更新 3:
最终更新:解决了这个问题,非常感谢 Michael Burr。

事实证明,其中一个构建使用 32 位时间,_USE_32BIT_TIME_T 在其中定义,另一个使用 64 位时间。所以它为对象生成了不同的布局,附上差异文件。

【问题讨论】:

  • DLL 是否有可能是用不同版本的类编译的?
  • 你能发布一段最小的、完整的代码来重现这个吗?
  • 听起来你的 exe 和 dll 使用不同的编译器(对齐)标志。
  • @Kerrek SB 我不知道这是否足够,由于限制,我无法提供实际代码。对不起。
  • Nasgul,您不必发布您的实际代码,但您确实需要发布演示您描述的问题的代码。如果您不能发布您的真实代码,那么请编写一些表现出相同问题的新代码。首先显示module->initModuleClass 函数之间的关系。如果您的函数具有相同数量的参数,这将有所帮助。

标签: c++ windows visual-studio dll


【解决方案1】:

您的 DLL 可能是使用不同的编译器选项集(甚至可能是稍微不同的头文件)编译的,因此类布局也不同。

例如,如果一个是使用调试标志构建的,而另一个不是,或者即使使用了不同的编译器版本。例如,不同编译器版本使用的库可能存在细微差别,如果您的类包含由库定义的类型,您可能会有不同的布局。

作为一个具体的例子,微软的编译器迭代器和容器对发布/调试、 _SECURE_SCL 开/关和 _HAS_ITERATOR_DEBUGGING 开/关设置很敏感(至少在 VS 2008 - VS 2010 可能已经将其中一些更改为一定程度上)。有关详细信息,请参阅http://connect.microsoft.com/VisualStudio/feedback/details/352699/secure-scl-is-broken-in-release-builds

这些问题使得跨 DLL 边界使用 C++ 类比使用直接 C 接口更脆弱。它们也可以出现在 C 结构中,但 C++ 库似乎更频繁地存在这些差异(我认为这是具有更丰富功能的本质)。

另一个不时发生的布局更改问题是在不同的编译中具有不同的结构打包选项。可以“隐藏”这一点的一件事是,编译指示通常用于标头中以将结构打包设置为某个值,有时您可能会遇到一个标头,该标头在不将其更改回默认值的情况下执行此操作(或更准确地说是以前的设置)。如果您有这样的标头,很容易将其包含在一个模块的构建中,而不是另一个模块。

【讨论】:

  • @Nasgul:好的,所以最近更新中的差异确认了class VM_Platform 布局在两个模块之间是不同的。我认为您需要仔细查看构建之间的编译器版本/选项的差异。仔细查看VM_PlatformVM_SourceRegistry 的定义也可能会提供线索。一个只输出sizeof(VM_Platform) 和/或sizeof(VM_SourceRegistry) 的小程序可以很容易地尝试不同的选项,看看它们有什么效果。
  • 非常感谢,我认为 VM_SourceRegistry 的大小存在差异,因为其中一个具有 _USE_32BIT_TIME_T 宏,因此另一个使用 64 位时间,因此不兼容。如果我浪费了你太多时间,我很抱歉,但我在解决这个问题时学到了很多东西,所以没有遗憾。再次非常感谢。发布差异
  • 我仍然有一个疑问 - 为什么vfptr 的大小不同?其中一个有 32 位,另一个有 64 位
  • @Nasgul:vfptr 的大小可能并没有什么不同;编译器可能只是在安排事情以确保嵌入的 time_t 值将是 64 位对齐的。
【解决方案2】:

这听起来有点奇怪,你应该展示更多代码,如果它被 ref 传递,它应该“移动”,听起来更像是在制作它的副本并且调用了成员函数。

也许 DLL 版本是针对您引用的不同版本编译的。检查并确保头文件与 dll 的版本相同。

如果可以的话,重新编译库。

【讨论】:

    猜你喜欢
    • 2021-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多