类本身的函数与其对象的函数地址不同的原因是什么?

huangapple go评论73阅读模式
英文:

How the function of the class itself has a different address from its objects' functions' addresses?

问题

我知道在类中,每个对象的变量在内存中都有不同的地址。但是,成员函数的地址在对象之间是共享的,因此只有一个函数以共同的地址加载到内存中。

问题是,我试图打印类本身某个成员函数的地址,我期望它与所有对象的成员函数地址相同。但我发现它与它们不同!对我来说这很奇怪。

#include<iostream>
using namespace std;

class LuckyNum {
public:
    void PrintAddress() {
        printf("\tFunction address: %p\n", &LuckyNum::PrintAddress);
    }
};

int main() {
    LuckyNum r1;
    cout << "r1:\n";
    r1.PrintAddress();

    LuckyNum r2;
    cout << "r2:\n";
    r2.PrintAddress();

    cout << "LuckyNum Class:\n";
    printf("\tFunction address: %p\n", &LuckyNum::PrintAddress);

    return 0;
}

/*输出结果!! :
r1:
Function address :0000007acdbffda0
r2:
Function address :0000007acdbffda0
LuckyNum Class:
Function address :0000007acdbffde0 => 为什么会这样!!它应该与上面两个地址相等,不是吗?


<details>
<summary>英文:</summary>

I know in classes that each object&#39;s variables will have a different address in memory. However, member functions&#39; addresses are common between objects, so only one function is loaded in memory with a common address.

The issue is I was trying to print the address of a certain member function of the class itself and I expected it to be the same as the member function&#39;s address of all objects. But I found that it&#39;s different from them!! That was very strange for me.

    #include&lt;iostream&gt;
    using namespace std;
        
    class LuckyNum {
        public:
            void PrintAddress() {
                printf(&quot;\tFunction address :%p\n&quot;, &amp;LuckyNum::PrintAddress);
            }
    };
        
    int main() {
        LuckyNum r1;
        cout &lt;&lt; &quot;r1:\n&quot;;
        r1.PrintAddress();

        LuckyNum r2;
        cout &lt;&lt; &quot;r2:\n&quot;;
        r2.PrintAddress();

        cout &lt;&lt; &quot;LuckyNum Class:\n&quot;;
        printf(&quot;\tFunction address :%p\n&quot;, &amp;LuckyNum::PrintAddress);

        return 0;
    }

    /*Output!! :
    r1:
        Function address :0000007acdbffda0
    r2:
        Function address :0000007acdbffda0
    LuckyNum Class:
        Function address :0000007acdbffde0 =&gt; HOW!! it should equal the above two addresses, shouldn&#39;t it?
    */

</details>


# 答案1
**得分**: 3

```plaintext
printf("\tFunction address :%p\n", &LuckyNum::PrintAddress);
printf("\tFunction address :%p\n", &LuckyNum::PrintAddress); 会引发未定义行为。 `printf` 不是类型安全的,`&LuckyNum::PrintAddress` 不是一个指针。它是一个_成员指针_,这是一种非常不同的东西,其表示是实现定义的。请参见以下程序:

#include
#include
#include

class LuckyNum {
public:
std::vector getAddress() {
auto const address = &LuckyNum::getAddress;
std::vector result(sizeof(address));
std::memcpy(result.data(), &address, sizeof(address));
return result;
}
};

int main() {
LuckyNum r;
auto address = r.getAddress();

auto const address2 = &LuckyNum::getAddress;
if (address.size() != sizeof(address2)) {
    std::cout << "Fail\n";
    return -1;
}
int result = std::memcmp(address.data(), &address2, address.size());
if (result != 0) {
    std::cout << "Fail\n";
    return -1;
}
std::cout << "Success\n";
return 0;

}

`getAddress()` 函数将成员指针 `&LuckyNum::getAddress` 存储在字节向量中并返回它。然后,`main` 通过 `getAddress()` 函数获取一个成员指针,然后直接通过 `&LuckyNum::getAddress` 获取另一个成员指针。然后,它逐字节比较 [如果运行程序](https://godbolt.org/z/qfT83jxEj)(至少使用 gcc),您会发现这两个成员指针确实相等。
英文:

The function call

printf(&quot;\tFunction address :%p\n&quot;, &amp;LuckyNum::PrintAddress);

invokes undefined behaviour. printf is not typesafe, and &amp;LuckyNum::PrintAddress is not a pointer. It is a pointer to member, which is a very different thing and it's representation is implementation defined.
See the following program:

#include &lt;iostream&gt;
#include &lt;vector&gt;
#include &lt;cstring&gt;

class LuckyNum {
public:
    std::vector&lt;char&gt; getAddress() {
        auto const address = &amp;LuckyNum::getAddress;
        std::vector&lt;char&gt; result(sizeof(address));
        std::memcpy(result.data(), &amp;address, sizeof(address));
        return result;
    }
};
 
int main() {
    LuckyNum r;
    auto address = r.getAddress();
 
    auto const address2 = &amp;LuckyNum::getAddress;
    if (address.size() != sizeof(address2)) {
        std::cout &lt;&lt; &quot;Fail\n&quot;;
        return -1;
    }
    int result = std::memcmp(address.data(), &amp;address2, address.size());
    if (result != 0) {
        std::cout &lt;&lt; &quot;Fail\n&quot;;
        return -1;
    }
    std::cout &lt;&lt; &quot;Success\n&quot;;
    return 0;
}

The getAddress() function stores the pointer to member &amp;LuckyNum::getAddress in a vector of bytes and returns it. main then obtains one pointer to member via the getAddress() function and another one directly via &amp;LuckyNum::getAddress. Then it compares to the byte by byte and if you run the program (with gcc at least) you will find that the two pointers to member are indeed equal.

huangapple
  • 本文由 发表于 2023年7月20日 08:54:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76726030.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定