如何用cout打印函数指针?

ibr*_*ead 49 c++

我想用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类型的右值.

这是为函数指针指定的唯一转换.

  • +1.适用于函数指针的唯一标准转换是(保存左值到右值转换)转换为`bool`.值得注意的是,你必须执行`reinterpret_cast`将`int(*)()`转换为`void*`. (4认同)
  • 最终文档将是C++标准,第4节[conv]和5.2 [expr.post].该标准不是免费的,但您可以在此处获取最新的草稿:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n3000.pdf.请注意,如果你不习惯,它很难阅读. (3认同)
  • @Neil:`void *` 是唯一的*转换*,但还有一点要记住:操纵器是您将其地址传递给流的函数。流不是转换它们,而是*调用*它们;如果您将指针传递给具有类似于操纵器的签名的函数,则流会将其视为操纵器,并调用该函数而不是尝试转换其地址。 (2认同)

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)


Gre*_*con 7

您可以将函数指针视为该函数的机器代码中第一条指令的地址.任何指针都可以被视为bool:0为假,其他一切都为真.正如您所观察到的,当void *转换为流插入操作符(<<)的参数并将其作为参数给出时,将打印该地址.(严格来看,将指向函数的指针转换void *为未定义.)

没有演员,故事有点复杂.为了匹配重载函数("重载决策"),C++编译器收集一组候选函数,并根据需要使用隐式转换从这些候选函数中选择"最可行"函数.皱纹是匹配规则形成偏序,因此多个最佳可行匹配会导致歧义错误.

按照优先顺序,标准转换(当然还有用户定义和省略号转换,不详细)

  • 完全匹配(不需要转换)
  • 促销(例如,intfloat)
  • 其他转换

最后一个类别包括布尔转换,任何指针类型都可以转换为bool:0(或NULL)是false,其他一切都是true.后者显示为1传递给流插入操作符时.

为了得到0相反,你的初始化改变

pf = 0;
Run Code Online (Sandbox Code Playgroud)

请记住,使用零值常量表达式初始化指针会产生空指针.