简体   繁体   中英

Printing address of function by using pointer

I am trying to print a function pointer address two times using a printf statement shown in below code...

class B
{
public:
        int fun()
        {
        }
};

int main()
{
        int (B::*pb)()=&B::fun;
        printf("ptr:%x | %x\n",pb,pb);   //Output is ptr:8048730 | 0
}

when i am passing same variable to printf it should print the same value but after getting the result i am surprised.

Can anyone explain the reason for this or somewhere i am doing wrong.

gcc version 4.8.2 (GCC)

If you turn on the warnings (pass the -Wall flag to the compiler), the compiler will tell you what you are doing wrong:

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]

In general, I can only encourage you to turn on warnings.

Now a hack (undefined behavior) is the following:

std::printf("ptr:%p | %p\\n",(void*)funcptr,(void*)funcptr);

This still gives the following warning:

warning: converting from 'int (B::*)()' to 'void*' [-Wpmf-conversions]

but the program prints the same address twice as you wished. It is still undefined behavior, see How to format a function pointer? By following the accepted answer (code shamelessly stolen from there), one could print the address as follows:

#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;
}

According to that answer it is the only legal way to achieve this. It doesn't give any warning.

Pointer-to-member function holds the "relative address" of where the function is in the class layout. Make the following change to the code:

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. 
}

A static member has no "part of the class". You can make other test, just try to print the address of a non-member function.

You can find more about pointer to member functions here .

The reason this is happening is that:

  1. pb (as written) is a pointer-to-member-function, not an ordinary pointer to function.
  2. The size of a pointer-to-member-function is unknown; it may or may not be the same as the size of other pointers, or of unsigned integers. It could easily be more than the 'usual' 32-bits (4 bytes), as it has more info to encode.
  3. The %x format specifier is for unsigned integers only. Assuming the 'usual' architecture, that means 32-bits or 4 bytes.
  4. The vargs calling sequence used by printf simply pulls two unsigned ints off the argument list and prints them. If the arguments passed to it don't match then the printed arguments don't line up and what you see is what you get.

I could speculate on exactly what the various numbers might be, but without knowing the compiler it's hard to be sure. I tried it on VS2010 and got a perfectly sensible 6 byte integer printed twice. Go figure.

You can prove it to yourself by taking the sizeof for that pointer (which should be more than 4), or by changing it into a pointer-to-function, which is almost always the same size as other pointers.

Please note that the standard does not guarantee anything about the size of pointers to functions as compared to other pointers. The precise meaning or behaviour of %p and whether it works with function pointers is not guaranteed either.

as we all know, a function ptr is equivalent to a 32bit unsigned number on a 32bit machine, so, if you want to see the value of a func ptr, you can use reinterpret_cast to convert it to a unsigned int

unsigned int a = reinterpret_cast<unsigned int>(fptr);
cout << hex << a << endl;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM