You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++函数/对象指针获取限制及相关编译问题咨询

C++指针转换与地址获取常见问题解答

测试代码

#include <print>

int var {};

void foo()
{
}

struct Bar
{
    char mem;

    void func()
    {
    }
};

Bar b {};

int main()
{
    // nullptr
    std::println( "{}", static_cast<const void*>( nullptr ) );
    // pointer to object
    std::println( "{}", static_cast<const void*>( &var ) );
    // pointer to function
    std::println( "{}", reinterpret_cast<const void*>( &foo ) );
    // pointer to member variable
    std::println( "{}", static_cast<const void*>( &Bar::mem ) ); // doesn't compile
    std::println( "{}", static_cast<const void*>( &(b.mem) ) );
    std::println( "{}", static_cast<const void*>( &(b.*(&Bar::mem)) ) );
    // pointer to member function
    std::println( "{}", reinterpret_cast<const void*>( &Bar::func ) ); // compiles with a warning
    std::println( "{}", reinterpret_cast<const void*>( &(b.func) ) ); // doesn't compile
    std::println( "{}", reinterpret_cast<const void*>( &(b.*(&Bar::func)) ) ); // doesn't compile

    // Did I miss any other category?
}

问题1:为何static_cast<const void*>( &Bar::mem )编译失败(&(b.*(&Bar::mem))可正常编译)?

编译器报错:

error: invalid 'static_cast' from type 'char Bar::*' to type 'const void*'

解答

&Bar::mem是成员变量指针,类型为char Bar::*,它不是指向内存地址的普通指针,而是记录了成员在类中的偏移信息,和普通对象指针属于完全不同的类型系统。C++标准明确禁止用static_cast将成员变量指针直接转换为void*。

而&(b.*(&Bar::mem))是先把成员指针&Bar::mem绑定到具体对象b上,得到的是b对象中mem成员的实际内存地址,此时它的类型是char*——普通对象指针,自然可以用static_cast转换成const void*。


问题2:为何无法获取绑定成员函数的地址?

编译器报错:

ISO C++ forbids taking the address of a bound member function to form a pointer to member function.  Say '&Bar::func'

解答

绑定到对象的成员函数(比如b.func)不是独立的函数实体,C++标准直接禁止获取这种绑定后的成员函数地址。要获取成员函数的指针,必须用&Bar::func的形式,得到的是void (Bar::*)()类型的成员函数指针——这种指针必须和对象实例结合才能调用,不能把绑定后的成员函数当作普通函数取地址。

另外,b.*(&Bar::func)本质上等价于调用b.func(),是函数调用表达式,不是可获取地址的实体,所以也无法取地址。


问题3:哪些指针类型可安全获取(如打印用途)且不触发错误或未定义行为?成员函数指针是否不被允许?

解答

以下类型的指针可以安全转换为const void*用于打印,完全符合标准且无未定义行为:

  • nullptr:直接用static_cast<const void*>(nullptr)转换即可,打印结果通常代表空地址。
  • 对象指针:包括普通变量指针(如&var)、对象成员的实际地址(如&b.mem),这类指针指向具体的内存对象,用static_cast<const void*>转换合法。

其他类型的情况:

  • 普通函数指针:可以用reinterpret_cast<const void*>转换后打印,这属于实现定义行为(不同编译器处理可能有差异),但主流编译器(GCC、Clang、MSVC)都支持,不会触发未定义行为。
  • 成员变量指针:不能直接转void*,但绑定到具体对象后得到的成员实际地址(普通对象指针)可以安全转换。
  • 成员函数指针:C++标准不允许将其转换为void*,哪怕用reinterpret_cast也属于未定义行为,编译器可能给出警告甚至拒绝编译,绝对不要这么做。

你还可以测试数组指针、void*本身等类型,它们都属于普通指针范畴,可安全转换为const void*。


内容的提问来源于stack exchange,提问作者digito_evo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 12:22:36