How to print function pointers with cout?
Asked Answered
H

7

60

I want to print out a function pointer using cout, and found it did not work.

But, it worked after I converted the function pointer to void*, so does printf with %p, such as:

#include <iostream>
using namespace std;

int foo() {return 0;}

int main()
{
    int (*pf)();
    pf = foo;
    cout << "cout << pf is " << pf << endl;
    cout << "cout << (void *)pf is " << (void *)pf << endl;
    printf("printf(\"%%p\", pf) is %p\n", pf);
    return 0;
}

I compiled it with g++ and got results like this:

cout << pf is 1  
cout << (void *)pf is 0x100000b0c  
printf("%p", pf) is 0x100000b0c

So, what does cout do with type int (*)()? I was told that the function pointer is treated as bool, is it true?

And, what does cout do with type void*?


EDIT: Anyhow, we can observe the content of a function pointer by converting it into void* and printing it out using cout. But, it does not work for member function pointers, and the compiler complains about an illegal conversion. I know that member function pointers is rather a complicated structure other than simple pointers, but how can we observe the content of a member function pointer?

Higa answered 14/1, 2010 at 14:22 Comment(0)
B
50

There actually is an overload of the << operator that looks something like:

ostream & operator <<( ostream &, const void * );

which does what you expect - outputs in hex. There can be no such standard library overload for function pointers, because there are infinite number of types of them. So the pointer gets converted to another type, which in this case seems to be a bool - I can't offhand remember the rules for this.

Edit: The C++ Standard specifies:

4.12 Boolean conversions

1 An rvalue of arithmetic, enumeration, pointer, or pointer to member type can be converted to an rvalue of type bool.

This is the only conversion specified for function pointers.

Bronder answered 14/1, 2010 at 14:27 Comment(8)
+1. The only standard conversion applicable to a pointer to function is (save for the lvalue-to-rvalue conversion) the conversion to bool. Notably, you must perform reinterpret_cast to convert int (*)() to void *.Stickleback
@Stickleback Is there a document or so covering the conversion rules of function pointers?Higa
The ultimate document would be the C++ standard, sections 4[conv] and 5.2[expr.post]. The standard isn't free, but you can get the latest draft here: open-std.org/jtc1/sc22/wg21/docs/papers/2009/n3000.pdf. Beware that it can difficult to read if you're not used to it.Stickleback
@Neil:void * is the only conversion, but there's another thing to keep in mind: manipulators are functions whose addresses you pass to the stream. Instead of converting them, the stream invokes them; if you pass a pointer to a function with a signature like a manipulator's, the stream will treat it like a manipulator, and invoke the function instead of attempting to convert its address at all.Fighter
@Neil Butterworth @avkar Thank you very much for your help. So cout will treat function pointers as bool after finding out there's not any other type possible to be converted to, right?Higa
@Jerry void * isn't really a conversion - you have to do a cast to get it to call the operator. The chances of someone writing a manipulator by accident seem pretty remote to me, though no doubt it has happened.Bronder
@Higa Well, it's not exactly cout doing it. Remember op<<() is just another function, so the normal parameter conversion rules apply.Bronder
The "infinite number of types of them" can now be handled by a single variadic template overload of operator<< with C++11 (see my answer).Telegraphese
S
11

Regarding your edit, you can print out contents of anything by accessing it via unsigned char pointer. An example for pointers to member functions:

#include <iostream>
#include <iomanip>

struct foo { virtual void bar(){} };
struct foo2 { };
struct foo3 : foo2, foo { virtual void bar(){} };

int main()
{
    void (foo3::*p)() = &foo::bar;

    unsigned char const * first = reinterpret_cast<unsigned char *>(&p);
    unsigned char const * last = reinterpret_cast<unsigned char *>(&p + 1);

    for (; first != last; ++first)
    {
        std::cout << std::hex << std::setw(2) << std::setfill('0')
            << (int)*first << ' ';
    }
    std::cout << std::endl;
}
Stickleback answered 14/1, 2010 at 15:24 Comment(1)
Thanks a lot! Now I know how to observe the content of member function pointer.Higa
E
8

You can think of a function pointer as being the address of the first instruction in that function's machine code. Any pointer can be treated as a bool: 0 is false and everything else is true. As you observed, when cast to void * and given as an argument to the stream insertion operator (<<), the address is printed. (Viewed strictly, casting a pointer-to-function to void * is undefined.)

Without the cast, the story is a little complex. For matching overloaded functions ("overload resolution"), a C++ compiler gathers a set of candidate functions and from these candidates selects the "best viable" one, using implicit conversions if necessary. The wrinkle is the matching rules form a partial order, so multiple best-viable matches cause an ambiguity error.

In order of preference, the standard conversions (and of course there also user-defined and ellipsis conversions, not detailed) are

  • exact match (i.e., no conversion necessary)
  • promotion (e.g., int to float)
  • other conversions

The last category includes boolean conversions, and any pointer type may be converted to bool: 0 (or NULL) is false and everything else is true. The latter shows up as 1 when passed to the stream insertion operator.

To get 0 instead, change your initialization to

pf = 0;

Remember that initializing a pointer with a zero-valued constant expression yields the null pointer.

Eclecticism answered 14/1, 2010 at 14:26 Comment(3)
So you mean compiler tends to treat any pointer without a known type as bool?Higa
@curiousguy Uh... Actually I mean when the compiler cannot find the exact signature of the function called as the arguments given, say a pointer of function in this specific example, the compiler will then try to convert it to bool and thus match an overloaded version with argument of bool type.Higa
@Higa Actually the compiler will always consider all possible candidates functions; if there is a function taking the correct function type, it will be the "best" candidate. Since there is no such function, the only candidate is the function taking bool.Zsolway
T
3

In C++11 one could modify this behavior by defining a variadic template overload of operator<< (whether that is recommendable or not is another topic):

#include<iostream>
namespace function_display{
template<class Ret, class... Args>
std::ostream& operator <<(std::ostream& os, Ret(*p)(Args...) ){ // star * is optional
    return os << "funptr " << (void*)p;
}
}

// example code:
void fun_void_void(){};
void fun_void_double(double d){};
double fun_double_double(double d){return d;}

int main(){
    using namespace function_display;
    // ampersands & are optional
    std::cout << "1. " << &fun_void_void << std::endl; // prints "1. funptr 0x40cb58"
    std::cout << "2. " << &fun_void_double << std::endl; // prints "2. funptr 0x40cb5e"
    std::cout << "3. " << &fun_double_double << std::endl; // prints "3. funptr 0x40cb69"
}
Telegraphese answered 17/11, 2013 at 20:20 Comment(6)
You also need an overload that will take a C-style variadic function (with its trailing ellipsis) and eight overloads for pointers to member functions, each of which can be unqualified, const, volatile, or const volatile and may or may not have a trailing ellipsis.Lugar
@Brian, do you mean to cover the case of a const pointer to function? like double(const *ptr)(double) = &fun_double_double;? (feel free to edit the answer to clarify).Telegraphese
You can't put const in that position. You'd want to put it just before ptr, if you want a constant pointer to function. Anyway, that case is already covered by your answer, but I mean something like double (T::*ptr)(double) const.Lugar
@Brian, yes, according to my tests const is covered (in fact const or not, it is the same function, the const is redundant). Yes, the pointer-to-member-function was not covered. I interpreted it was not part of the question. But I added it to the answer now.Telegraphese
@Brian, at tried to generalize the solution but I couldn't template<class Ret, class T, class... Args> std::ostream& operator <<(std::ostream& os, Ret(T::* const p)(Args...) const){ // first const ins optional return os << "memfunptr const " << typeid(T).name() <<"::"<< reinterpret_cast<size_t const*>(&p); } but basically all distinct member functions print the same number.Telegraphese
@alfC, I managed to do it here: Is possible to fix the iostream cout/cerr member function pointers being printed as 1 or true?Fari
G
2

Casting pointers to (void*) to print them to cout is the right thing (TM) to do in C++ if you want to see their values.

Goddamn answered 14/1, 2010 at 14:31 Comment(2)
It's the right thing to do, except of course where it doesn't work at all. Unfortunately, there's no guarantee that a pointer to code is really compatible with a pointer to data. A classic example (truly classic, nowadays) was in the "medium" memory model under MS-DOS, where a pointer to data was only 16 bits, but a pointer to code was 32 bits.Fighter
@JerryCoffin unsigned long, unsigned long long can be used too.Zsolway
M
1

Regarding your specific question,

how can we observe the content of a member function pointers?

The answer is, other than converting them to bool to express that it points to something or it doesn't, you can't 'observer' member function pointers. At least not in a compliant way. The reason is because the standard explicitly disallows this:

4.12 footnote 57:

57) The rule for conversion of pointers to members (from pointer to member of base to pointer to member of derived) appears inverted compared to the rule for pointers to objects (from pointer to derived to pointer to base) (4.10, clause 10). This inversion is necessary to ensure type safety. Note that a pointer to member is not a pointer to object or a pointer to function and the rules for conversions of such pointers do not apply to pointers to members. In particular, a pointer to member cannot be converted to a void*.

For example, here is sample code:

#include <cstdlib>
#include <vector>
#include <algorithm>
#include <string>
#include <iostream>
using namespace std;

class Gizmo
{
public:
    void DoTheThing()
    {
        return;
    };


private:
    int foo_;
};

int main()
{
    void(Gizmo::*fn)(void) = &Gizmo::DoTheThing;

    Gizmo g;
    (g.*fn)();  // once you have the function pointer, you can call the function this way

    bool b = fn;
//  void* v = (void*)fn;    // standard explicitly disallows this conversion
    cout << hex << fn;
    return 0;
}

I note that my debugger (MSVC9) is able to tell me the actual physical address of the member function at runtime, so I know there must be some way to actually get that address. But I'm sure it is non-conformant, non-portable and probably involves machine code. If I were to go down that road, I would start by taking the address of the function pointer (eg &fn), casting that to void*, and go from there. This would also require you know the size of pointers (different on different platforms).

But I would ask, so long as you can convert the member-function pointer to bool and evaluate the existance of the pointer, why in real code would you need the address?

Presumably the answer to the last question is "so I can determine if one function pointer points to the same function as another." Fair enough. You can compare function pointers for equality:

#include <cstdlib>
#include <vector>
#include <algorithm>
#include <string>
#include <iostream>
using namespace std;

class Gizmo
{
public:
    void DoTheThing()
    {
        return;
    };

    **void DoTheOtherThing()
    {
        return;
    };**


private:
    int foo_;
};

int main()
{
    void(Gizmo::*fn)(void) = &Gizmo::DoTheThing;

    Gizmo g;
    (g.*fn)();  // once you have the function pointer, you can call the function this way

    bool b = fn;
//  void* v = (void*)fn;    // standard explicitly disallows this conversion
    cout << hex << fn;

    **void(Gizmo::*fnOther)(void) = &Gizmo::DoTheOtherThing;

    bool same = fnOther == fn;
    bool sameIsSame = fn == fn;**

    return 0;
}
Mullah answered 14/1, 2010 at 15:53 Comment(3)
@John Dibling Thank you very much for your answer. Actually, I'm just curious about the content of member function pointer and that's why I want to print it to check out. :) And, there's several "**" which would cause the compiler to complain. ;)Higa
Part of the standard you are quoting has nothing to do with the answer asked. Pointer to member is totally different thing than pointer to method (that is pointer to member function).Binary
@SergeDundich: Your comment makes no sense -- a pointer to member function is a pointer to member (the other kind of pointer to member is a pointer to non-static data member). All pointers to members (both function and data) get formed the same way, using &Type::member, and used the same way, using .* or ->*.Curt
B
0

maybe (in one time I stay intersecting about the address of function) one of decision )))

#include <iostream>     
#include <stdlib.h>

void alexf();

int main()
{ 
    int int_output;

    printf("printf(\"%%p\", pf) is %p\n", alexf);

    asm( "movl %[input], %%eax\n"                
         "movl %%eax, %[output]\n" 
         : [output] "+m" (int_output)
         : [input] "r" (&alexf)
         : "eax", "ebx"
    );

        std::cout<<"" <<std::hex<<int_output <<""<<std::endl;
    return 0;
}

void  alexf() {  }

passing the pointer to function (&alexf) or other pointer using & use constraint r. Let gcc to use register for input argument)).

Barquisimeto answered 26/7, 2019 at 11:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.