I want to print out a function pointer using cout, and found it did not work. But it worked after I converting 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 *)?
Thanks in advance.
EDIT: Anyhow, we can observe the content of a function pointer by converting it into (void *) and print it out using cout. But it does not work for member function pointers and the compiler complains about the 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 pointers?
Regarding your edit, you can print out contents of anything by accessing it via
unsigned char
pointer. An example for pointers to member functions:There actually is an overload of the << operator that looks something like:
which does what you expect - outputs in hex. There can be no such standard library overload for function pointers, because are are an 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:
This is the only conversion specified for function pointers.
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):Regarding your specific question,
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:
For example, here is sample code:
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:
Casting pointers to
(void*)
to print them tocout
is the right thing (TM) to do in C++ if you want to see their values.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 tovoid *
and given as an argument to the stream insertion operator (<<
), the address is printed. (Viewed strictly, casting a pointer-to-function tovoid *
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
int
tofloat
)The last category includes boolean conversions, and any pointer type may be converted to
bool
: 0 (orNULL
) isfalse
and everything else istrue
. The latter shows up as1
when passed to the stream insertion operator.To get
0
instead, change your initialization toRemember that initializing a pointer with a zero-valued constant expression yields the null pointer.