【问题标题】:Cast pointer to member function to intptr_t将指向成员函数的指针转换为 intptr_t
【发布时间】:2013-09-15 16:30:46
【问题描述】:

问题:有没有办法在 C++ 中将指向成员函数的指针转换为 intptr_t?

已知因素:

  1. 我知道成员函数指针很特别
  2. 我知道成员函数传递隐藏的“this”参数(__thiscall)。
  3. 我知道 sizeof(member function pointer) > sizeof(intptr_t) 在某些情况下, 在这个问题中,我只谈论可能的情况,即在我的情况下 sizeof(member function pointer) == sizeof(intptr_t)。
  4. 最后我知道将指针转换为 intptr_t 不是一个好的模式。

示例代码:

class test // No inheritance, in the case I need
    {
    public:
    void func();    // No virtual, or any special modifiers in the case I need
    };

void main2()
    {
    intptr_t p = &test::func;
    };

我知道一个解决方法来做这个演员,但我不喜欢它,因为它需要一个临时变量:

void my_way()
    {
    intptr_t p;
    auto t = &test::func;       // Temp variable, I don't like the fact I need to use it, but I have no other way for now
    p = *reinterpret_cast<intptr_t*>(&t);
    };

所以问题是如何将技巧内联作为右值表达式,没有临时变量(也没有相同的 memcpy)。

例子:

reinterpret_cast<??>(???_cast<??>(???_cast<??>( &test::func )))

(我不在乎表情有多美)。

-------------(下面是一些关于为什么的想法,而不是问题)----------- ---------------------

这个网站上有一些类似的主题,但他们大多都在谈论“你为什么这样做?”或“你为什么需要这个?”,谈论这个可以解决提问的人的问题,但不适合我。

我为什么需要这个员工:我正在编写某种任务,我决定实现我自己的动态链接机制。 可以有几个特定的​​应用程序。

在我的例子中——动态链接机制——我想将一个指向函数的指针传递给另一个模块。 我有一个类和一个接口作为一个单独的结构(我知道,有相同方法的库)。 众所周知,使用这种机制的所有类都是普通的(根本没有继承,所以没有虚拟等)。 所有这些都在 x86 32 位上运行,或者最多在 64 个 Windows 上运行,由 MSVC 2012 编译。 由于接口与类完全隔离,因此它使用指针数组。 Lib 将数组传递给主机进程。 在主机进程中我有这个......这甚至不是一个“问题”,但仍然:

inline int my_interface::func_name(int param)
    {
    decltype(&interface_name::func_name) temp;
    *((intptr_t*)&temp) = reinterpret_cast<interface_name::funcs*>(interface_desc->funcs)->func_name;
    return (reinterpret_cast<decltype(this)>(object)->*temp)(param);
    };

这是一个内联函数,所以我希望它尽可能小,如果可能的话,我想消除“temp”,因为我不确定编译器是否会正确消除它,即使使用所有优化。

其他应用(假设): - 如果我想用特定的守卫来保护我的成员函数所在的内存页面怎么办。 WinAPI 为我提供了一种方法,但它需要页面的地址。 对于正常功能,这样做没有问题,但对于成员 - 仅使用我描述的 WA?或者有什么办法? - 如果我想在运行时修补图像怎么办? IE。找到一些 const 并用另一个替换它? 运行时修补至少有几个原因:2.1 动态链接重定位过程,2.2 代码混淆。

这只是一个说明 - 读者经常问“为什么”,我不想讨论为什么,因为在我看来可以有很多应用程序,所有这些都不是为新手准备的,但更多的是为安全人员等...

我特此请求不要讨论“为什么这样做?”,“为什么不使用 dll/boost/其他库/其他语言的现有机制?”在这个线程中。

【问题讨论】:

  • 请注意,还有一个额外的因素:sizeof(mfp) == sizeof(intptr_t) 是否取决于您使用的编译器,而不仅仅是类型。看看你的编译器是否接受到(void*) 的中间转换,但就正确性而言,你自己。
  • 不能通过强制转换来完成:指向成员的指针只能强制转换为其他指向成员的指针,即使使用reinterpret_cast。不幸的是,没有什么可引用的,因为标准只指定了允许的类型转换。但是,您可以使用指向成员的指针的“memcpy”(即,通过使用指向成员的指针复制指向成员的内容)。
  • 鉴于您自己的第 4 点,您能解释一下为什么您还是要这样做吗?例如,您是否试图找到一种方法来为任意对象的 mfps 创建一个通用容器?
  • 扩展解释“为什么”。
  • (如果您是put an @ before a user name in a comment,则会通知用户。将始终通知问题/答案的创建者。)使用memcpy 的替代方法是使用unionLive example 注意: 这是未定义的行为,因此最好在编译器的文档中查看它的作用。 (应该没问题。)

标签: c++ pointers function-pointers member-function-pointers member-functions


【解决方案1】:

不,规范不允许您将函数指针或成员指针转换为 intptr_t。原因是您可能需要不止一个 intptr_t 的数据来描述它们。例如,gcc 上的成员指针长度为 3 个 intptr_t,MSCV 的长度范围为 1 到 4 个 intptr_t。其中大部分用于处理虚函数。

在一些旧硬件(C++ 支持)上,指针实际上也比函数指针小。这发生在小型系统上,您可能只需要指向 8 位内存结构,但程序会被加载到 16 位程序内存空间中。

很多时候,您尝试使用的这种模式用于创建委托:永久绑定到特定对象的成员函数指针。这可以通过 2 个 int 指针和一个包装函数来完成

struct Delegate
{
    intptr_t   obj;  // I'll use intptr_t here, but often this is void*
    intptr_t   func;
};

// you need one of these for each type of mfp you use
static void callT_Test(intptr_t obj)
{
    T* realObj = reinterpret_cast<T*>(obj);
    realObj->test();
}

// constructing a delegate to call test on t
Delegate d;
d.obj = reinterpret_cast<intptr_t>(&t);
d.func = &callT_Test;

【讨论】:

  • 感谢您的直接回答。
  • 我也是这么想的,但我不能离开这个问题,直到我找到一个证明。吃我的是:如果不可能,那么 C++ 会试图禁止我访问函数的二进制图像的地址。 IE。代码驻留在内存中的地方。
  • 更准确地说,C++ 没有提供官方认可的方法来访问函数的二进制映像。如果它提供了一种官方认可的方法,那么它将限制 C++ 的使用在满足该官方认可方法要求的平台上。例如,其中一些嵌入式平台实际上确实禁止访问代码的二进制映像(它们被称为哈佛架构)。现在,如果您愿意亲自动手,并且是特定于编译器和平台的,那么可以通过特定于编译器的方法来做您想做的事情。
  • 例如,这里有一篇很棒的文章的链接,该文章试图通过以编译器特定的方式分解成员函数指针来实现快速委托。这些就是你正在谈论的事情。 codeproject.com/Articles/7150/…
  • 不同意你的看法。仅当无法将普通函数转换为 int 时,您的论点才是合法的,但是有 - 您只需 reinterpret_cast 它。这意味着 C++ 确实允许您获取指向“代码的二进制图像”的指针,由于某些未知原因,仅禁止指向类成员的指针。很抱歉发布了 necroposting。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-10
  • 2011-09-22
  • 1970-01-01
相关资源
最近更新 更多