C++ 如何使用 cout 打印函数指针?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2064692/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to print function pointers with cout?
提问by ibread
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 *) 之后它起作用了,printf 和 %p 也是如此,例如
#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 0x100000b0c
cout << 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 对类型 (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 将其打印出来来观察它的内容。但它不适用于成员函数指针,编译器会抱怨非法转换。我知道成员函数指针是一个复杂的结构而不是简单的指针,但是我们如何观察成员函数指针的内容呢?
采纳答案by ibread
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:
编辑:C++ 标准规定:
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.
4.12 布尔转换
1 算术、枚举、指针或指向成员类型的指针的右值可以转换为 bool 类型的右值。
This is the only conversion specified for function pointers.
这是为函数指针指定的唯一转换。
回答by avakar
Regarding your edit, you can print out contents of anything by accessing it via unsigned char
pointer. An example for pointers to member functions:
关于您的编辑,您可以通过unsigned char
指针访问它来打印任何内容。指向成员函数的指针的示例:
#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;
}
回答by Greg Bacon
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
) - other conversions
- 完全匹配(即,无需转换)
- 推广(例如,
int
到float
) - 其他转换
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
)是false
,其他一切都是true
。后者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.
请记住,使用零值常量表达式初始化指针会产生空指针。
回答by alfC
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 中,可以通过定义一个可变参数模板重载来修改这种行为operator<<
(是否值得推荐是另一个主题):
#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"
}
回答by Eli Bendersky
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.
如果您想查看它们的值,将指针转换为(void*)
将它们打印到cout
是在 C++ 中做的正确的事情 (TM)。
回答by John Dibling
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) 能够在运行时告诉我成员函数的实际物理地址,所以我知道必须有某种方法来实际获取该地址。但我确信它不符合标准,不可移植,并且可能涉及机器代码。如果我要沿着这条路走下去,我会从获取函数指针(例如&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;
}
回答by Alexey Chizhenko
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)).
(&alexf)
使用&
use constraint将指针传递给函数 或其他指针r
。让我们gcc
使用 register 作为输入参数))。