使用指针打印功能地址

时间:2014-05-22 13:31:33

标签: c++ c++11

我正在尝试使用下面代码中显示的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)

4 个答案:

答案 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)

发生这种情况的原因是:

  1. pb(写成)是一个指向成员的函数,不是普通的函数指针。
  2. 指向成员函数的指针的大小未知;它可能与其他指针或无符号整数的大小相同或不同。它可能很容易超过通常的&#39; 32位(4字节),因为它有更多信息要编码。
  3. %x格式说明符仅适用于无符号整数。假设通常&#39;体系结构,这意味着32位或4个字节。
  4. printf使用的vargs调用序列只是将两个无符号整数从参数列表中拉出并打印出来。如果传递给它的论点不匹配,那么印刷的论点就不会排成一行,你所看到的就是你得到的。
  5. 我可以推测出各种数字究竟是什么,但是在不知道编译器的情况下很难确定。我在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;