Visual Studio中指向类数据成员的C++指针的地址

Xin*_*ang 4 c++ pointers visual-studio

我正在读" Inside the C++ Object Model "一书.书中有一个例子:

struct Base1
{
    int v1;
};

struct Base2
{
    int v2;
};

class Derived : public Base1, public Base2 {};

printf("&Derived::v1 = %p\n", &Derived::v1);        // Print 0 in VS2008/VS2012
printf("&Derived::v2 = %p\n", &Derived::v2);        // Print 0 in VS2008/VS2012
Run Code Online (Sandbox Code Playgroud)

在前面的代码中,地址Derived :: v1&Derived :: v2的打印都是0.但是,如果通过变量打印相同的地址:

int Derived::*p;
p = &Derived::v1;
printf("p = %p (&Derived::v1)\n", p);        // Print 0 in VS2008/VS2012 as before
p = &Derived::v2;
printf("p = %p (&Derived::v2)\n", p);        // Print 4 in VS2008/VS2012
Run Code Online (Sandbox Code Playgroud)

通过检查&Derived :: v1和p的大小,我得到4.

// Both are 4
printf("Size of (&Derived::v1) is %d\n", sizeof(&Derived::v1));
printf("Size of p is %d\n", sizeof(p));
Run Code Online (Sandbox Code Playgroud)

Derived :: v1 的地址为0,但Derived :: v2的地址为4.我不明白为什么&Derived :: v2 在分配给变量时变为4.

检查汇编代码,当直接查询Derived :: v2的地址时,它被转换为0 ; 但是当它分配给变量时,它会被转换为4.

我在VS2008和VS2012上测试过,结果是一样的.所以我认为必须有一些理由让微软选择这样的设计.

而且,如果你喜欢这样:

d1.*(&Derived::v2) = 1;
Run Code Online (Sandbox Code Playgroud)

显然&派生:: v2不是0.为什么编译器会区分这两种情况?

任何人都可以告诉后面发生的事情吗?谢谢!

- 编辑 -

对于那些认为&Derived :: v1没有获得有效地址.你有没有这样做过?

Derived d1, d2;
d1.*p = 1;
d2.*p = 1;
Run Code Online (Sandbox Code Playgroud)

Her*_*ter 5

海报问我这个问题,起初我也怀疑有类似的错误原因.这不是VC++特有的.

事实证明,正在发生的事情是,类型&Derived::v2不是int Derived::*,但是int Base2::*,它自然会有零偏移,因为它是相对于Base2的偏移.当您将其显式转换为a时int Derived::*,将更正偏移量.

在VC++或GCC或Clang上尝试这个代码......我正在使用stdio/printf.

struct Base1 { int a; };
struct Base2 { int b; };
struct Derived : Base1, Base2 { };

#include <cassert>
#include <cstdio>
#include <typeinfo>
using namespace std;

int main () {

   printf( "%s\n", typeid(&Derived::a).name() );  // mentions Base1
   printf( "%s\n", typeid(&Derived::b).name() );  // mentions Base2

   int Derived::* pdi = &Derived::b;  // OK
   int Base2::*   p2i = &Derived::b;  // OK
   //int Base1::* p1i = &Derived::b;  // ERROR

   assert( sizeof(int*) == sizeof(pdi) );
   printf( "%p %p", p2i, pdi );  // prints "(nil) 0x4" using GCC 4.8 at liveworkspace.org

}
Run Code Online (Sandbox Code Playgroud)