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
我想用cout打印一个函数指针,结果发现它不工作。但是在我将函数指针转换为(void *)之后,它就可以工作了,使用%p的printf也可以工作,例如
#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:
我用g++编译,得到如下结果:
cout << pf is 1
cout << (void *)pf is 0x100000b0c
printf("%p", pf) is 0x100000b0ccout < pf是1 cout < (void *)pf是0x100000b0c printf(“%p”,pf)是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 *)?
那么cout对int(*)()类型做了什么?我被告知函数指针被当作bool,是真的吗?cout对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?
编辑:无论如何,我们可以通过将函数指针转换为(void *)并使用cout将其打印出来来观察函数指针的内容。但是它不适用于成员函数指针,编译器会抱怨非法转换。我知道成员函数指针是一个复杂的结构而不是简单的指针,但是我们如何观察成员函数指针的内容呢?
6 个解决方案
#1
39
There actually is an overload of the << operator that looks something like:
实际上,< <操作符的重载是这样的:< p>
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 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.
这就是你期望的-输出hex。函数指针不可能有这样的标准库重载,因为它们的类型是无限的。所以指针被转换成另一种类型,在这种情况下,看起来是bool,我不能马上记住这个的规则。
Edit: The C++ Standard specifies:
编辑:c++标准指定:
4.12 Boolean conversions
4.12逻辑转换
1 An rvalue of arithmetic, enumeration, pointer, or pointer to member type can be converted to an rvalue of type bool.
算术、枚举、指针或成员类型指针的rvalue可以转换为bool类型的rvalue。
This is the only conversion specified for function pointers.
这是函数指针指定的惟一转换。
#2
9
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;
}
#3
4
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.)
可以将函数指针看作是函数机器代码中的第一个指令的地址。任何指针都可以被当作bool: 0是假的,其他的都是真的。正如您所观察到的,当转换为void *并作为流插入操作符(<<)的参数给出时,地址将被打印出来。(严格地说,将指针转换为void *是没有定义的。)
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.
没有演员,故事有点复杂。对于匹配重载函数(“重载解析”),c++编译器收集一组候选函数,从这些候选函数中选择“最佳可行”函数,必要时使用隐式转换。皱纹是匹配规则形成的部分顺序,因此多个最佳匹配会导致歧义错误。
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
tofloat
) - 促销(例如,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.
最后一个类别包括布尔转换,任何指针类型都可以转换为bool: 0(或NULL)是假的,其他一切都是正确的。当传递给流插入操作符时,后者显示为1。
To get 0
instead, change your initialization to
要得到0,请将初始化更改为。
pf = 0;
Remember that initializing a pointer with a zero-valued constant expression yields the null pointer.
记住,用零值常量表达式初始化指针会产生空指针。
#4
0
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.
如果您想要查看它们的值,那么在c++中将指针转换为(void*)并将它们打印到cout是正确的做法(TM)。
#5
0
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:
答案是,除了把它们转换成bool来表示它指向什么或者没有,你不能“观察者”成员函数指针。至少不符合标准。原因是,该标准明确禁止:
4.12 footnote 57:
4.12脚注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*.
57)将指针转换为成员的规则(从指针到成员的指针到派生的成员的指针)与指向对象指针的规则(从指针到指针到基的指针)相比较(4.10,第10条)。这种倒置对于确保类型安全是必要的。注意,指向成员的指针不是指向对象的指针,也不是指向函数的指针,而这些指针的转换规则并不适用于指向成员的指针。特别是,指向成员的指针不能转换为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).
我注意到我的调试器(MSVC9)能够在运行时告诉我成员函数的实际物理地址,因此我知道必须有某种方法来实际获得该地址。但我确信它是不一致的,不可移植的,可能涉及到机器代码。如果我沿着这条路走下去,我会从函数指针(eg &fn)的地址开始,将它转换为void*,然后从那里开始。这还需要知道指针的大小(在不同的平台上不同)。
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?
但我想问的是,只要你能将成员函数指针转换为bool并计算指针的存在性,为什么在真正的代码中你需要这个地址呢?
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;
}
#6
0
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):
在c++ 11中,我们可以通过定义操作符<< << <的变量模板重载来修改这个行为(是否推荐是另一个主题):< p>
#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"
}
#1
39
There actually is an overload of the << operator that looks something like:
实际上,< <操作符的重载是这样的:< p>
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 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.
这就是你期望的-输出hex。函数指针不可能有这样的标准库重载,因为它们的类型是无限的。所以指针被转换成另一种类型,在这种情况下,看起来是bool,我不能马上记住这个的规则。
Edit: The C++ Standard specifies:
编辑:c++标准指定:
4.12 Boolean conversions
4.12逻辑转换
1 An rvalue of arithmetic, enumeration, pointer, or pointer to member type can be converted to an rvalue of type bool.
算术、枚举、指针或成员类型指针的rvalue可以转换为bool类型的rvalue。
This is the only conversion specified for function pointers.
这是函数指针指定的惟一转换。
#2
9
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;
}
#3
4
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.)
可以将函数指针看作是函数机器代码中的第一个指令的地址。任何指针都可以被当作bool: 0是假的,其他的都是真的。正如您所观察到的,当转换为void *并作为流插入操作符(<<)的参数给出时,地址将被打印出来。(严格地说,将指针转换为void *是没有定义的。)
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.
没有演员,故事有点复杂。对于匹配重载函数(“重载解析”),c++编译器收集一组候选函数,从这些候选函数中选择“最佳可行”函数,必要时使用隐式转换。皱纹是匹配规则形成的部分顺序,因此多个最佳匹配会导致歧义错误。
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
tofloat
) - 促销(例如,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.
最后一个类别包括布尔转换,任何指针类型都可以转换为bool: 0(或NULL)是假的,其他一切都是正确的。当传递给流插入操作符时,后者显示为1。
To get 0
instead, change your initialization to
要得到0,请将初始化更改为。
pf = 0;
Remember that initializing a pointer with a zero-valued constant expression yields the null pointer.
记住,用零值常量表达式初始化指针会产生空指针。
#4
0
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.
如果您想要查看它们的值,那么在c++中将指针转换为(void*)并将它们打印到cout是正确的做法(TM)。
#5
0
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:
答案是,除了把它们转换成bool来表示它指向什么或者没有,你不能“观察者”成员函数指针。至少不符合标准。原因是,该标准明确禁止:
4.12 footnote 57:
4.12脚注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*.
57)将指针转换为成员的规则(从指针到成员的指针到派生的成员的指针)与指向对象指针的规则(从指针到指针到基的指针)相比较(4.10,第10条)。这种倒置对于确保类型安全是必要的。注意,指向成员的指针不是指向对象的指针,也不是指向函数的指针,而这些指针的转换规则并不适用于指向成员的指针。特别是,指向成员的指针不能转换为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).
我注意到我的调试器(MSVC9)能够在运行时告诉我成员函数的实际物理地址,因此我知道必须有某种方法来实际获得该地址。但我确信它是不一致的,不可移植的,可能涉及到机器代码。如果我沿着这条路走下去,我会从函数指针(eg &fn)的地址开始,将它转换为void*,然后从那里开始。这还需要知道指针的大小(在不同的平台上不同)。
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?
但我想问的是,只要你能将成员函数指针转换为bool并计算指针的存在性,为什么在真正的代码中你需要这个地址呢?
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;
}
#6
0
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):
在c++ 11中,我们可以通过定义操作符<< << <的变量模板重载来修改这个行为(是否推荐是另一个主题):< p>
#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"
}