1

Meet a very weird problem, anyone know what is the reason of this? the code is tested under Visual Studio 2012.

#include <iostream>
struct A {
  int a;
};
struct B {
  int b;
};
struct C : public A, public B {
  int c;
};

int main() {
  int C::*p = &C::b;
  std::printf("%p\n", &C::b); //00000000
  std::printf("%p\n", p);     //00000004
  return 0;
}
Xiaotian Pei
  • 3,210
  • 21
  • 40

2 Answers2

2

Pointers to members are not just plain C-pointers, so passing them to printf is actually undefined behavior, because printf will believe in the "%p" and C-cast the pointer-to-member to void*.

The only conversions of pointers to members allowed by the standard are listed in paragraph 4.11:

  1. Null-pointer constants can be converted to null member pointer values
  2. B::*T can be converted to D::*T if B is an accessible, nonambiguos and nonvirtual baseclass of D.

Pointers to members can actually have different sizes depending on the classes they point into.

See here for more info on pointer-to-member implementations in MSVC: http://blogs.msdn.com/b/oldnewthing/archive/2004/02/09/70002.aspx

Arne Mertz
  • 24,171
  • 3
  • 51
  • 90
  • I disassembly the code, and I found 0 is pushed as parameter for printf. There is no cast here. – Xiaotian Pei Aug 29 '13 at 12:30
  • The problem with disassembly here is that once the compiler generates machine code you've lost all the type information which explains why the numbers are what they are. The hidden part in this case is in the "int C::*p = &C::b;" part because it isn't doing what you think it's doing. – Speed8ump Aug 29 '13 at 16:42
0

Note the possibly unexpected result of:

printf("typeid(&C::b) = %s\n",typeid(&C::b).name());
printf("typeid(&B::b) = %s\n",typeid(&B::b).name());

Which on VS2010 yields:

typeid(&C::b) = int B::*
typeid(&B::b) = int B::*

This indicates that the resulting type for &C::b is a member pointer on type B. Since C is derived from B the pointer is freely convertible to a member pointer on type C. This explains the difference between the two values you see. &C::b is a member function pointer on type B, int C::*p is a member function pointer on type C.

int B::*p_b = &B::b;
int C::*p_c = p_b;
printf("p_b = %p\n", p_b);
printf("p_c = %p\n", p_c);
Speed8ump
  • 1,307
  • 10
  • 25