调用dll函数时,参数对象的成员变量的内存地址会发生变化

时间:2012-02-27 21:33:23

标签: c++ windows visual-studio dll

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

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

问题

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

详情

调用之前

(来自exe):

             '&(this).one_of_the_mem_' - `0x00e913d0`
在之后

- 在dll本身中:

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

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

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

代码:

Exe的代码

  

stat = module-> init(这个,                                   object_a,                                              &安培; object_b,                                              object_c,   con_dir                                            );

DLL中的代码

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

更新1:

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

更新2:

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

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

更新3: Class layout difference between exe and dll, but don't know why yet
最终更新:解决了这个问题,非常感谢Michael Burr。

原来,其中一个版本使用了32位时间,其中定义了_USE_32BIT_TIME_T,另一个使用了64位时间。因此它为对象生成了不同的布局,附加的是差异文件。

Diff in two classes due to sizeof `time_t'

2 个答案:

答案 0 :(得分:3)

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

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

作为一个具体的例子,使用Microsoft的编译器迭代器和容器对发布/调试,_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 ++库更经常地存在这些差异(我认为这是具有更丰富功能的本质)。

不时出现的另一个布局变化问题是在不同的编译中有不同的结构打包选项。可以“隐藏”这一点的一点是,pragma通常用于标题中以将结构打包设置为某个值,有时您可能遇到一个标题,这样做而不将其更改回默认值(或者更准确地说是先前的设置) )。如果你有这样的标题,很容易将它包含在一个模块的构建中,而不是另一个模块。

答案 1 :(得分:0)

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

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

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