我正在尝试使用下面代码中显示的printf
语句两次打印函数指针地址...
class B
{
public:
int fun()
{
}
};
int main()
{
int (B::*pb)()=&B::fun;
printf("ptr:%x | %x\n",pb,pb); //Output is ptr:8048730 | 0
}
当我将同一个变量传递给printf
时,它应该打印相同的值,但在得到结果后我感到很惊讶。
任何人都可以解释这个或我做错的地方的原因。
gcc version 4.8.2 (GCC)
答案 0 :(得分:2)
如果你打开警告(将-Wall
标志传递给编译器),编译器会告诉你你做错了什么:
warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int (B::*)()’ [-Wformat]
warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘int (B::*)()’ [-Wformat]
一般来说,我只能鼓励你打开警告。
现在黑客(未定义的行为)如下:
std::printf("ptr:%p | %p\n",(void*)funcptr,(void*)funcptr);
这仍然会发出以下警告:
warning: converting from ‘int (B::*)()’ to ‘void*’ [-Wpmf-conversions]
但程序会根据您的意愿打印两次相同的地址。它仍然是未定义的行为,请参阅How to format a function pointer?按照接受的答案(从那里无耻地窃取代码),可以按如下方式打印地址:
#include <cstdio>
class B {
public:
int fun() { return 0; }
};
int main()
{
int (B::*funcptr)()=&B::fun;
unsigned char *p = (unsigned char *)&funcptr;
for (unsigned int i = 0; i < sizeof funcptr; ++i)
{
std::printf("%02x ", p[i]);
}
std::putchar('\n');
return 0;
}
根据答案,这是实现这一目标的唯一合法途径。它没有给出任何警告。
答案 1 :(得分:0)
指向成员的函数保存&#34;相对地址&#34;功能在类布局中的位置。对代码进行以下更改:
class B
{
public:
static int fun() // Add static keyword
{
}
};
int main()
{
int (*pb)()=&B::fun; // Change B::*pb for *pb
// You should use %p instead of %x as suggested by @Praetorian
printf("ptr:%p | %p\n",pb,pb); //Now ouput is the same.
}
静态成员没有&#34;类#34;的一部分。您可以进行其他测试,只需尝试打印非成员函数的地址。
您可以找到有关成员函数here的指针的更多信息。
答案 2 :(得分:0)
发生这种情况的原因是:
我可以推测出各种数字究竟是什么,但是在不知道编译器的情况下很难确定。我在VS2010上尝试了它,得到了一个完全合理的6字节整数打印两次。去图。
您可以通过获取该指针的sizeof(应该大于4)或者将其更改为指向函数的指针来证明自己,这几乎总是与其他指针的大小相同。
请注意,与其他指针相比,标准不保证函数指针的大小。 %p的确切含义或行为以及它是否与函数指针一起使用也不能保证。
答案 3 :(得分:0)
众所周知,函数ptr相当于32位机器上的32位无符号数,因此,如果要查看func ptr的值,可以使用reinterpret_cast将其转换为unsigned int
unsigned int a = reinterpret_cast<unsigned int>(fptr);
cout << hex << a << endl;