我想用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;
}
Run Code Online (Sandbox Code Playgroud)
我用g ++编译它并获得如下结果:
cout << pf是1
cout <<(void*)pf是0x100000b0c
printf("%p",pf)是0x100000b0c
那么cout对int(*)()类型做了什么?我被告知函数指针被视为bool,是真的吗?cout用type(void*)做什么?
提前致谢.
编辑:无论如何,我们可以通过将函数指针转换为(void*)并使用cout将其打印出来来观察函数指针的内容.但它对成员函数指针不起作用,编译器抱怨非法转换.我知道成员函数指针是一个比简单指针更复杂的结构,但是我们如何才能观察成员函数指针的内容呢?
小智 42
实际上<<运算符的重载看起来像:
ostream & operator <<( ostream &, const void * );
Run Code Online (Sandbox Code Playgroud)
这符合您的期望 - 十六进制输出.函数指针不能有这样的标准库重载,因为它们是无数种类型的.所以指针转换为另一种类型,在这种情况下似乎是一个布尔 - 我不能随便记住这个规则.
编辑: C++标准指定:
4.12布尔转换
1算术,枚举,指针或指向成员类型的指针的右值可以转换为bool类型的右值.
这是为函数指针指定的唯一转换.
ava*_*kar 11
关于编辑,您可以通过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;
}
Run Code Online (Sandbox Code Playgroud)
您可以将函数指针视为该函数的机器代码中第一条指令的地址.任何指针都可以被视为bool
:0为假,其他一切都为真.正如您所观察到的,当void *
转换为流插入操作符(<<
)的参数并将其作为参数给出时,将打印该地址.(严格来看,将指向函数的指针转换void *
为未定义.)
没有演员,故事有点复杂.为了匹配重载函数("重载决策"),C++编译器收集一组候选函数,并根据需要使用隐式转换从这些候选函数中选择"最可行"函数.皱纹是匹配规则形成偏序,因此多个最佳可行匹配会导致歧义错误.
按照优先顺序,标准转换(当然还有用户定义和省略号转换,不详细)
int
到float
)最后一个类别包括布尔转换,任何指针类型都可以转换为bool
:0(或NULL
)是false
,其他一切都是true
.后者显示为1
传递给流插入操作符时.
为了得到0
相反,你的初始化改变
pf = 0;
Run Code Online (Sandbox Code Playgroud)
请记住,使用零值常量表达式初始化指针会产生空指针.