C++ 如何使用cout打印函数指针?
我想用cout打印出一个函数指针,但发现它不起作用。 但是在我将函数指针转换为(void*)之后,它就工作了,带有%p的printf也是如此,例如C++ 如何使用cout打印函数指针?,c++,C++,我想用cout打印出一个函数指针,但发现它不起作用。 但是在我将函数指针转换为(void*)之后,它就工作了,带有%p的printf也是如此,例如 #include <iostream> using namespace std; int foo() {return 0;} int main() { int (*pf)(); pf = foo; cout << "cout << pf is " << pf <<
#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;
}
#包括
使用名称空间std;
int foo(){return 0;}
int main()
{
int(*pf)();
pf=foo;
cout您可以将函数指针视为该函数机器代码中第一条指令的地址。任何指针都可以视为bool
:0为false,其他所有内容均为true。正如您所观察到的,当转换为void*
并作为流插入运算符的参数提供时(实际上有大量的投射指针到(void*)
将它们打印到cout
是正确的(TM)要在C++中做,如果你想看到它们的值。< /P> < P>关于你的编辑,你可以通过通过<代码>未签名char < /Cube指针访问它来打印任何内容。
#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;
}
#包括
#包括
结构foo{virtualvoidbar(){}};
结构foo2{};
结构foo3:foo2,foo{virtualvoidbar(){}};
int main()
{
void(foo3::*p)(=&foo::bar;
unsigned char const*first=重新解释强制转换(&p);
unsigned char const*last=reinterpret_cast(&p+1);
for(;first!=last;++first)
{
关于你的具体问题
我们怎样才能观察一份报告的内容
成员函数指针
答案是,除了将它们转换为bool以表示它指向某个对象或不指向某个对象之外,您不能“观察者”成员函数指针。至少不能以兼容的方式。原因是该标准明确禁止:
4.12脚注57:
57)货币兑换规则
指向成员的指针(从指针到
指向的成员的指针的基成员
派生)与
指向对象的指针的规则(从
指向派生的指针(指向基的指针)
(4.10,第10条)。此倒置为
确保类型安全所必需的。注意
指向成员的指针不是
指向对象的指针或指向对象的指针
函数和转换规则
这些指针的任何一个都不适用于
指向成员的指针。尤其是
无法转换指向成员的指针
空荡荡的*
例如,下面是示例代码:
#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;
}
在C++11中,可以通过定义操作符maybe的可变模板重载来修改此行为(有一次,我一直与函数的地址相交)
(决定之一)
#包括
#包括
void-alexf();
int main()
{
整数输出;
printf(“printf(\“%%p\”,pf)是%p\n”,alexf);
asm(“movl%[输入],%%eax\n”
“movl%%eax,%[输出]\n”
:[输出]“+m”(整数输出)
:[input]“r”(&alexf)
:“eax”、“ebx”
);
std::cout+1。唯一适用于函数指针的标准转换是(左值到右值的转换除外)到bool
的转换。值得注意的是,您必须执行重新解释
才能转换int(*)()<代码> >代码> Vult*/Cux> .avavar是否有一个文档覆盖函数指针的转换规则?最终文件将是C++标准,第4节[CONV]和5.2 [ExPR.PoST ]。该标准不是免费的,但您可以在此处获得最新的草稿:。请注意,如果您不习惯,则可能很难阅读。@Neil:void*
是唯一的转换,但要记住另一件事:操纵器是将其地址传递给流的函数。如果您需要,流将调用它们,而不是转换它们将一个指针传递给一个具有类似于操纵器的签名的函数,流会将其视为操纵器,并调用该函数,而不是试图转换其地址。@Neil Butterworth@avkar非常感谢您的帮助。因此,cout在发现没有任何其他类型的可能后,会将函数指针视为bool要转换为,对吗?那么你的意思是编译器倾向于将任何没有已知类型的指针视为bool?@curiousguy呃…实际上我的意思是当编译器找不到作为给定参数调用的函数的确切签名时,比如在这个特定示例中的函数指针,编译器会尝试将其转换为bool,从而匹配一个带有BOOL类型的参数的重载版本。@ IBULL实际上编译器总是考虑所有可能的候选函数;如果有一个函数取正确的函数类型,它将是“最佳”。候选函数。由于没有这样的函数,唯一的候选函数是采用bool
的函数。这是正确的做法,当然,除非它根本不起作用。不幸的是,无法保证代码指针与数据指针真正兼容。一个经典的例子(现在真正经典的)是在“媒体”中MS-DOS下的内存模型,其中指向数据的指针只有16位,而指向代码的指针是32位。@JerryCoffinunsigned long
,unsigned long
也可以使用。非常感谢!现在我知道了如何观察成员函数指针的内容。@John Dibling非常感谢你的回答。实际上,我只是好奇而已关于成员函数指针的内容,这就是为什么我要打印它以进行检查。:)并且,有几个“**”会导致编译器抱怨。;)您引用的部分标准与所问的答案无关。指向成员的指针与指向方法的指针完全不同(那是指向成员函数的指针)。@SergeDundich:你的评论毫无意义——指向成员函数的指针就是指向成员的指针(指向成员的另一种指针是指向非静态数据成员的指针)。所有指向成员的指针(函数和数据)使用&Type::member
以相同的方式生成表单,并使用*
或以相同的方式生成表单
#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;
}
#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;
}
#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;
}
#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"
}