繁体   English   中英

从功能结构成员获取功能地址

[英]Get function address from a function structure member

我正在尝试获取隐藏在结构后面的函数地址。 不幸的是, void*基本的C ++转换void* ,因此我改用C++ template

1.基本 void* C ++转换不适用于结构内部的函数,为什么?

void * lpfunction;
lpfunction = scanf; //OK
lpfunction = MessageBoxA; //OK

我做了一个简单的结构:

struct FOO{

    void PRINT(void){printf("bla bla bla");}

    void SETA(int){} //nothing you can see
    void SETB(int){} //nothing you can see

    int GETA(void){} //nothing you can see
    int GETB(void){} //nothing you can see
};
///////////////////////////////////////////
void *lpFunction = FOO::PRINT;

和编译错误:

error C2440: 'initializing' : 
cannot convert from 'void (__thiscall FOO::*)(void)' to 'void *'

2.是否无法获得职能成员地址?

然后,我制作了一个模板函数,该函数能够将函数成员转换为地址。 然后我将通过汇编进行调用。 应该是这样的:

template <class F,void (F::*Function)()>  
void * GetFunctionAddress() {

    union ADDRESS  
    { 
        void (F::*func)();  
        void * lpdata;  
    }address_data;  

    address_data.func = Function;  
    return address_data.lpdata; //Address found!!!  

}  

这是代码:

int main()
{
    void * address = GetFunctionAddress<FOO,&FOO::PRINT>();

    FOO number;
    number.PRINT(); //Template call
    void * lpdata = &number;

  __asm mov ecx, lpdata //Attach "number" structure address __asm call address //Call FOO::PRINT with assembly using __thiscall 

printf("Done.\n");
system("pause");
return 0;
}

但是,我认为它非常具体 看起来像LOCK-KEY ,我必须为每个参数类型集创建一个新模板。

原稿(确定):

void PRINT(); //void FOO::PRINT();

修改一下:

void PRINT(int); //void FOO::PRINT(int);

立即使用旧模板代码,编译器显示:

//void (F::*func)();
//address_data.func = Function;

 error C2440: '=' : cannot convert from 'void (__thiscall FOO::*)(int)' to 'void (__thiscall FOO::*)(void)' 

为什么? 它们只是地址。

69:       address_data.func = Function;
00420328  mov  dword ptr [ebp-4],offset @ILT+2940(FOO::PRINT) (00401b81)

...

EDIT3:我知道更好的解决方案:

void(NUMBER::*address_PRINT)(void) = FOO::PRINT;
int(NUMBER::*address_GETA)(void) = FOO::GETA;
int(NUMBER::*address_GETB)(void) = FOO::GETB;
void(NUMBER::*address_SETA)(int) = FOO::SETA;
void(NUMBER::*address_SETA)(int) = FOO::SETB;

它比template好得多。 而且我想实现这个目标:

<special_definition> lpfunction;
lpfunction = FOO::PRINT; //OK
lpfunction = FOO::GETA; //OK
lpfunction = FOO::GETB; //OK
lpfunction = FOO::SETA; //OK
lpfunction = FOO::SETB; //OK

这可能吗?

指向成员函数的指针与指向全局函数或静态成员函数的指针完全不同。 造成这种情况的原因很多,但我不确定您对C ++的工作方式了解多少,因此我不确定哪些原因是有意义的。

我确实知道您在汇编中尝试的操作在一般情况下根本行不通。 似乎您对成员函数和函数指针的用途有基本的误解。

问题是,您正在做一些C ++中通常不会做的事情。 通常,您不会在C ++中建立函数指针表,因为您将要使用的东西就是virtual函数。

如果您确定要使用这种方法,建议您不要使用C ++,而只能使用C。

为了证明这些指针类型是完全不兼容的,下面是一个程序供您使用:

#include <cstdio>

struct Foo {
   int a;
   int b;
   int addThem() { return a + b; }
};

struct Bar {
   int c;
   int d;
   int addThemAll() { return c + d; }
};

struct Qux : public Foo, public Bar {
   int e;
   int addAllTheThings() { return Foo::addThem() + Bar::addThemAll() + e; }
};

int addThemGlobal(Foo *foo)
{
   return foo->a + foo->b;
}

int main()
{
   int (Qux::*func)();

   func = &Bar::addThemAll;
   printf("sizeof(Foo::addThem) == %u\n", sizeof(&Foo::addThem));
   printf("sizeof(Bar::addThemAll) == %u\n", sizeof(&Bar::addThemAll));
   printf("sizeof(Qux::addAllTheThings) == %u\n", sizeof(&Qux::addAllTheThings));
   printf("sizeof(func) == %u\n", sizeof(func));
   printf("sizeof(addThemGlobal) == %u\n", sizeof(&addThemGlobal));
   printf("sizeof(void *) == %u\n", sizeof(void *));
   return 0;
}

在我的系统上,该程序产生以下结果:

$ /tmp/a.out 
sizeof(Foo::addThem) == 16
sizeof(Bar::addThemAll) == 16
sizeof(Qux::addAllTheThings) == 16
sizeof(func) == 16
sizeof(addThemGlobal) == 8
sizeof(void *) == 8

注意成员函数指针的长度为16个字节。 它不会适合一个void * 它不是正常意义上的指针。 您的代码和union纯属偶然。

原因是成员函数指针经常需要在其中存储额外的数据,这些数据与修复传递的对象指针有关,以便对所调用的函数正确。 在我的示例中,当在Qux对象上调用Bar::addThemAll (由于继承是完全有效的)时,需要在调用函数之前将指向Qux对象的指针调整为指向Bar子对象。 因此,成员函数的Qux::*必须在其中编码此调整。 毕竟,说func = &Qux::addAllTheThings是完全有效的,并且如果调用了该函数,则无需进行指针调整。 因此,指针调整是函数指针值的一部分。

那只是一个例子。 允许编译器以其认为合适的任何方式(在某些约束范围内)实现成员函数指针。 许多编译器(例如我在使用的64位平台上的GNU C ++编译器)将以不允许将任何成员函数指针都视为等同于正常函数指针的方式来实现它们。

有一些方法可以解决这个问题。 处理成员函数指针的瑞士军刀是C ++ 11或C ++ TR1中的::std::function模板。

一个例子:

 #include <functional>

 // .... inside main
    ::std::function<int(Qux *)> funcob = func;

funcob可以指向任何可以像函数一样调用且需要Qux * 成员函数,全局函数,静态成员函数,函子... funcob可以指向它。

该示例仅适用于C ++ 11编译器。 但是,如果您的编译器是相当新的,但仍不是C ++ 11编译器,则可以改用:

 #include <tr1/functional>

 // .... inside main
    ::std::tr1::function<int(Qux *)> funcob = func;

如果情况变得更糟,则可以使用Boost库,这是整个概念的来源。

但是我会重新考虑您的设计。 我怀疑,如果您对继承层次结构进行了深思熟虑并使用了virtual函数,那么与现在所做的一切相比,您将得到更多的好处。 使用解释器,我将拥有一个顶级抽象“表达式”类,该类是可评估的所有内容的抽象类。 我会给它一个虚拟的evaluate方法。 然后,您可以派生用于不同语法元素的类,例如加法表达式,变量或常量。 他们每个人都将针对其特定情况重载评估方法。 然后,您可以构建表达式树。

虽然不知道细节,但这只是关于您设计的模糊建议。

这是一个干净的解决方案。 通过模板将您的成员函数包装为静态成员函数。 然后,您可以将其转换为所需的任何指针:

template<class F, void (F::*funct)()>
struct Helper: public T {
  static void static_f(F *obj) {
    ((*obj).*funct)();
  };
};

struct T {
  void f() {
  }
};

int main() {
  void (*ptr)(T*);
  ptr = &(Helper<T,&T::f>::static_f);
}

看来您需要将指向成员函数的指针转换为void *。 我假设您想将该指针作为“用户数据”提供给某些库函数,然后您将取回指针并希望在某些给定对象上使用它。

如果是这种情况,那么reinterpret_cast<void *>(...)可能是正确的事情...我假设接收指针的库未使用它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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