Printing a pointer-to-member-field

折月煮酒 提交于 2019-12-11 10:53:22

问题


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?


回答1:


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';
}



回答2:


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.




回答3:


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.




回答4:


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;
}


来源:https://stackoverflow.com/questions/7826985/printing-a-pointer-to-member-field

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!