19

It looks like std::cout can't print member function's address, for example:

#include <iostream>

using std::cout;
using std::endl;

class TestClass
{
  void MyFunc(void);

public:
  void PrintMyFuncAddress(void);
};

void TestClass::MyFunc(void)
{
  return;
}

void TestClass::PrintMyFuncAddress(void)
{
  printf("%p\n", &TestClass::MyFunc);
  cout << &TestClass::MyFunc << endl;
}

int main(void)
{
  TestClass a;

  a.PrintMyFuncAddress();

  return EXIT_SUCCESS;
}

the result is something like this:

003111DB
1

How can I print MyFunc's address using std::cout?

EFanZh
  • 2,357
  • 3
  • 30
  • 63

4 Answers4

23

I don't believe that there are any facilities provided by the language for doing this. There are overloads for operator << for streams to print out normal void* pointers, but member function pointers are not convertible to void*s. This is all implementation-specific, but typically member function pointers are implemented as a pair of values - a flag indicating whether or not the member function is virtual, and some extra data. If the function is a non-virtual function, that extra information is typically the actual member function's address. If the function is a virtual function, that extra information probably contains data about how to index into the virtual function table to find the function to call given the receiver object.

In general, I think this means that it's impossible to print out the addresses of member functions without invoking undefined behavior. You'd probably have to use some compiler-specific trick to achieve this effect.

Hope this helps!

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • For some interesting statistics on the sizes and implementations of pointers-to-member-functions in various compilers, see the chart near the bottom of [this article](http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible). However, since that article is somewhat dated (written in 2005), the numbers are likely no longer accurate, but they give a rough idea. – Adam Rosenfield Jun 20 '12 at 02:32
14

I'd like to add to the other answers, that the reason that you are getting '1' printed instead of an address, is that, for some reason, the compiler is coercing your function pointer into a boolean, so that you are really calling ostream& operator<< (bool val);

This seems to be unrelated to the function being a member function.

You can uncover this kind of information with clang++ -cc1 -ast-dump:

(ImplicitCastExpr 0x3861dc0 <col:13, col:25> '_Bool' <MemberPointerToBoolean>
    (UnaryOperator 0x3861940 <col:13, col:25> 'void (class TestClass::*)(void)' prefix '&'
        (DeclRefExpr 0x38618d0 <col:14, col:25> 'void (void)' CXXMethod 0x3861500 'MyFunc' 'void (void)')))))
Panayiotis Karabassis
  • 2,278
  • 3
  • 25
  • 40
6

One way to do that is (I'm not sure it's portable) :

void TestClass::PrintMyFuncAddress(void)
{
  void (TestClass::* ptrtofn)() = &TestClass::MyFunc;
  cout << (void*&)ptrtofn<< endl;
}

working example : http://ideone.com/1SmjW

Mr.Anubis
  • 5,132
  • 6
  • 29
  • 44
  • 3
    That program demonstrate very little. That C-style cast is a `reinterpret_cast` which usually just reinterprets the memory as the destination type. In this case, it will use the first `sizeof(void*)` bytes stored in the pointer to member as if it was a `void*`, but if you check the sizes of both types you will see that they differ (pointer to member is bigger). – David Rodríguez - dribeas Jun 20 '12 at 02:48
  • @DavidRodríguez-dribeas: But it should (probably) print the same value as the "%p" of the printf(). They are both probably wrong (assuming member pointers are larger than normal pointers (usually true)). – Martin York Jun 20 '12 at 04:43
5

Pointers to member functions need memory, too. They also have a size. So how about printing out the memory of the pointer:

template<typename R, typename T, typename... Args>
std::string to_string(R (T::*func)(Args...))
{
    union PtrUnion
    {
        R(T::*f)(Args...);
        std::array<unsigned char, sizeof(func)> buf;
    };
    PtrUnion u;
    u.f = func;

    std::ostringstream os;

    os << std::hex << std::setfill('0');
    for (auto c : u.buf)
        os << std::setw(2) << (unsigned)c;

    return os.str();
}

You can use it this way:

class TestClass
{
    void foo();
};

...

std::cout << to_string(&TestClass::foo) << std::endl;
Databyte
  • 1,420
  • 1
  • 15
  • 24
  • Why using Union? – Evandro Coan Jan 10 '20 at 20:13
  • Because member pointers need more memory than `void*`, I believe 16 byte instead of 8 for a `void*` (on a 64bit architecture). So if you just print it as a `void*` you miss half of the pointer. But yes, you could also iterate directly over the memory of the pointer, I guess – Databyte Jan 11 '20 at 11:04