C++ sizeof(*此)给出了错误的值

C++ sizeof(*此)给出了错误的值,c++,assembly,sizeof,C++,Assembly,Sizeof,我有一个类,C.C有一个成员变量声明为:bool markerStart 在C中,对sizeof(*this)的调用给出了0x216字节的值 在C中的其他地方,我会这样做:markerStart=false 这个调用并没有将markerStart设置为false,实际上是在破坏内存中下一个类的开始 查看反汇编代码,我发现: markerStart = false; 06FB6B7F mov eax, dword ptr [this] 06FB6B78 mov

我有一个类,C.C有一个成员变量声明为:bool markerStart

在C中,对sizeof(*this)的调用给出了0x216字节的值

在C中的其他地方,我会这样做:markerStart=false

这个调用并没有将markerStart设置为false,实际上是在破坏内存中下一个类的开始

查看反汇编代码,我发现:

markerStart = false;
06FB6B7F mov            eax, dword ptr [this]
06FB6B78 mov            byte ptr [eax+218h], 0
第二条move指令将+0x218处的一个字节设置为零,但由于该类的长度只有0x216字节,因此这是在破坏内存

作为对注释的响应,它肯定是markerStart=false指令。我可以在反汇编程序视图和内存视图中观察它的发生(并使用Windbg,通过使用数据断点)。下一个类的第一个字节被设置为零,这会弄乱它的vftbl指针

注意:取markerStart的地址并从中减去它,得到0x211

有谁能告诉我从哪里着手解决这个问题的线索吗

更新:谢谢你的帮助。 如果没有代码,你们几乎不可能解决这个问题。我想要的是关于从哪里开始寻找的提示。你们大多数人都提供了很好的提示,所以谢谢你们


我终于找到了问题所在。在这种情况下,对齐已在一个类中设置,并且在关键代码块之后未正确重置。对齐错误的类恰好在声明类C之前被编译,因此问题就出现了。

该类可能只有0x216字节,但下一个对象当然是第一个对象开始后的0x218字节。您的对象显然是按4字节内存边界对齐的,这是默认值


你必须到别处去寻找你的记忆在哪里被破坏。这绝对不是“markerStart=false”指令。

您需要发布更多代码——如果您可以将其删减到发生异常的最小类定义,那就更好了。这本身可能会帮助你确定发生了什么

我想到的一些可能性:

  • 您正在引用另一个markerStart变量,该变量会隐藏您感兴趣的成员变量
  • 在基类C的方法中计算sizeof。sizeof()只测量静态类型,而不是动态类型
  • 您已经打破了“某处”,并且拥有两个不同版本的C类(可能是通过头文件中的一些#ifdef实现的,它在两个翻译单元中的解释不同)
    如果没有更多的信息,我会选择违反ODR。这些可能是隐蔽的,在编译或链接时无法检测到

    这可能是“类切片”问题的一个实例吗?

    您的类是否有虚拟方法?或者它是从具有虚拟方法的类派生的?或者你的类有多重继承


    答案取决于您使用的编译器,编译器可以存储指向虚拟表的指针。这确实是一个实现细节,但只要它与标准一样工作,它就可以用每个对象存储任何类型的数据。

    代码中没有一些奇怪的指针转换问题吗?类似的东西

    struct A
    {
      int i;
    };
    
    struct B : public A
    {
      int j;
      void f() { j=0; }
    };
    
    int main()
    {
      A x;
      A* p=&x;
      ((B*)p)->f();
      return 0;
    }
    

    你能不能检查一下,它实际上指向了一个C的实例,在这一行中,它正在破坏你的记忆?您是否可以在此时打印
    typeid(*this).name()
    (假设类具有一些虚拟函数)?

    您遇到的问题可能是由于某些依赖项错误,而不是编译器的任何错误(成百上千的开发人员都在使用编译器,如果有这样的问题,现在就已经发现了)

    考虑一个包含以下两个文件的简单项目。文件a.cpp:

    class C
    {
    public:
      C () : m_value (42) { }
      void Print () { cout << "C::m_value = " << m_value << endl; }
    private:
      int m_value;
    };
    
    void DoSomethingWithC (C &c);
    
    void main (void)
    {
      C array_of_c [2];
      DoSomethingWithC (array_of_c [0]);
      array_of_c [0].Print ();
      array_of_c [1].Print ();
    }
    
    如果编译上述两个文件并链接它们,则不会得到任何错误或警告。但是,当您运行应用程序时,您会发现DoSomethingWithC clobbers array_of_c[1],即使其参数是array_of_c[0]

    因此,您的问题可能是一个源文件以一种方式查看类,而另一个文件以另一种方式查看类。如果依赖性检查失败,可能会发生这种情况


    尝试强制全部重建。如果这样做有效,那么您需要了解依赖项失败的原因(例如,DevStudio有时会出错).

    正如Pontus所指出的,您可能以某种方式打破了“一个定义”规则。您可能已将带有C类定义的头文件包含在两个翻译单元中,其中其他代码(通常在前面的头文件中)更改了C类定义的解释方式,从而使其在两个翻译单元中具有不同的大小尼茨


    一种可能性是,您不小心更改了默认成员对齐方式(通过编译器的命令行参数或通过源代码中的#pragma),因此两个不同的翻译单元认为由于填充量不同,结构的大小不同(大多数x86编译器默认在4字节边界上对齐,但允许您根据需要请求在1字节边界上对齐)。在其他头文件中查找一个#pragma,更改缺少以下#prama的默认对齐,以将其恢复到以前的值(您没有指定哪个编译器,因此我无法给出详细信息).

    最近您的类定义或项目设置有任何更改吗?我看到过类似的问题,我遇到过这样的荒谬行为,原因是链接了过时的对象文件。对象文件不再与源文件匹配。请尝试干净完整的重建。

    检查*这是否真的指向t他开始上课,而不是通过一个坏指针来调用。< /p>发布一些实际的C++代码来说明问题,你能发布一些实际的代码吗?C的定义可能是一个很好的开始,可能是因为218!= 0x218 [EAX+2]是一个类型,一个
    class C
    {
    public:
      int a,b;
    };
    
    void DoSomethingWithC (C &c)
    {
      c.b = 666;
    }