Question

I was debugging some code involving pointers to member fields, and i decided to print them out to see their values. I had a function returning a pointer to member:

#include <stdio.h>
struct test {int x, y, z;};
typedef int test::*ptr_to_member;
ptr_to_member select(int what)
{
    switch (what) {
    case 0: return &test::x;
    case 1: return &test::y;
    case 2: return &test::z;
    default: return NULL;
    }
}

I tried using cout:

#include <iostream>
int main()
{
    std::cout << select(0) << " and " << select(3) << '\n';
}

I got 1 and 0. I thought the numbers indicated the position of the field inside the struct (that is, 1 is y and 0 is x), but no, the printed value is actually 1 for non-null pointer and 0 for null pointer. I guess this is a standard-compliant behavior (even though it's not helpful) - am i right? In addition, is it possible for a compliant c++ implementation to print always 0 for pointers-to-members? Or even an empty string?

And, finally, how can i print a pointer-to-member in a meaningful manner? I came up with two ugly ways:

printf("%d and %d\n", select(0), select(3)); // not 64-bit-compatible, i guess?

ptr_to_member temp1 = select(0); // have to declare temporary variables
ptr_to_member temp2 = select(3);
std::cout << *(int*)&temp1 << " and " << *(int*)&temp2 << '\n'; // UGLY!

Any better ways?

Was it helpful?

Solution

Member pointers aren't ordinary pointers. The overloads you expect for << aren't in fact there.

If you don't mind some type punning, you can hack something up to print the actual values:

int main()
{
  ptr_to_member a = select(0), b = select(1);
  std::cout << *reinterpret_cast<uint32_t*>(&a) << " and "
            << *reinterpret_cast<uint32_t*>(&b) << " and "
            << sizeof(ptr_to_member) << '\n';
}

OTHER TIPS

Pointers to members are not as simple as you may think. Their size changes from compiler to compiler and from class to class depending on whether the class has virtual methods or not and whether it has multiple inheritance or not. Assuming they are int sized is not the right way to go. What you can do is print them in hexadecimal:

void dumpByte(char i_byte)
{
    std::cout << std::hex << static_cast<int>((i_byte & 0xf0) >> 4);
    std::cout << std::hex << static_cast<int>(i_byte & 0x0f));
} // ()

template <typename T>
void dumpStuff(T* i_pStuff)
{
    const char* pStuff = reinterpret_cast<const char*>(i_pStuff);
    size_t size = sizeof(T);
    while (size)
    {
        dumpByte(*pStuff);
        ++pStuff;
        --size;
    } // while
} // ()

However, I'm not sure how useful that information will be to you since you don't know what is the structure of the pointers and what each byte (or several bytes) mean.

You can display the raw values of these pointer-to-members as follows:

#include <iostream>
struct test {int x, y, z;};
typedef int test::*ptr_to_member;
ptr_to_member select(int what)
{
    switch (what) {
    case 0: return &test::x;
    case 1: return &test::y;
    case 2: return &test::z;
    default: return NULL;
    }
}

int main()
  {
  ptr_to_member x = select(0) ;
  ptr_to_member y = select(1) ;
  ptr_to_member z = select(2) ;
  std::cout << *(void**)&x << ", " << *(void**)&y << ", " << *(void**)&z << std::endl ;
  }

You get warnings about breaking strict anti-aliasing rules (see this link), but the result is what you might expect:

0, 0x4, 0x8

Nevertheless, the compiler is free to implement pointer-to-member functionality however it likes, so you can't rely on these values being meaningful.

I think you should use printf to solve this problen

 #include <stdio.h>

struct test{int x,y,z;}
int main(int argc, char* argv[])
{
  printf("&test::x=%p\n", &test::x);
  printf("&test::y=%p\n", &test::y);
  printf("&test::z=%p\n", &test::z);
  return 0;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top