简体   繁体   English

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

[英]Get function address from a function structure member

I'm trying to get function addresses which are hidden behind structures. 我正在尝试获取隐藏在结构后面的函数地址。 Unfortunately, the void* basic C++ conversion doesn't work, so I used C++ template instead. 不幸的是, void*基本的C ++转换void* ,因此我改用C++ template

1. Basic void* C++ conversion doesn't work with functions inside structures, why? 1.基本 void* C ++转换不适用于结构内部的函数,为什么?

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

I made a simple structure : 我做了一个简单的结构:

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;

And the compiling error : 和编译错误:

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

2. Is getting function member addresses impossible? 2.是否无法获得职能成员地址?

Then, I made a template function which is able to convert a function member to address. 然后,我制作了一个模板函数,该函数能够将函数成员转换为地址。 Then I will call it by assembly. 然后我将通过汇编进行调用。 It should be something like this: 应该是这样的:

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!!!  

}  

And here is the code : 这是代码:

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

But, I see it is extremely specific . 但是,我认为它非常具体 It looks like LOCK - KEY , and I have to make a new template for every set of argument types. 看起来像LOCK-KEY ,我必须为每个参数类型集创建一个新模板。

Original (OK) : 原稿(确定):

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

Modify a bit : 修改一下:

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

Immediately with old template code the compiler shows : 立即使用旧模板代码,编译器显示:

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

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

Why? 为什么? They are only addresses. 它们只是地址。

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

... ...

EDIT3 : I know the better solution : 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;

It's much better than template . 它比template好得多。 And by the way I want to achieve the goal : 而且我想实现这个目标:

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

Is this possible? 这可能吗?

Pointers to member functions are nothing like pointers to global functions or static member functions. 指向成员函数的指针与指向全局函数或静态成员函数的指针完全不同。 There are many reasons for this, but I'm not sure how much you know about how C++ works, and so I'm not sure what reasons will make sense. 造成这种情况的原因很多,但我不确定您对C ++的工作方式了解多少,因此我不确定哪些原因是有意义的。

I do know that what you are trying in assembly simply won't work in the general case. 我确实知道您在汇编中尝试的操作在一般情况下根本行不通。 It seems like you have a fundamental misunderstanding about the purpose of member functions and function pointers. 似乎您对成员函数和函数指针的用途有基本的误解。

The thing is, you are doing some things that you would generally not do in C++. 问题是,您正在做一些C ++中通常不会做的事情。 You don't generally build up tables of function pointers in C++ because the things you would use that sort of thing for are what virtual functions are for. 通常,您不会在C ++中建立函数指针表,因为您将要使用的东西就是virtual函数。

If you are determined to use this approach, I would suggest you not use C++ at all, and only use C. 如果您确定要使用这种方法,建议您不要使用C ++,而只能使用C。

To prove these pointer types are completely incompatible, here is a program for you: 为了证明这些指针类型是完全不兼容的,下面是一个程序供您使用:

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

On my system this program yields these results: 在我的系统上,该程序产生以下结果:

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

Notice how the member function pointer is 16 bytes long. 注意成员函数指针的长度为16个字节。 It won't fit into a void * . 它不会适合一个void * It isn't a pointer in the normal sense. 它不是正常意义上的指针。 Your code and union work purely by accident. 您的代码和union纯属偶然。

The reason for this is that a member function pointer often needs extra data stored in it related to fixing up the object pointer it's passed in order to be correct for the function that's called. 原因是成员函数指针经常需要在其中存储额外的数据,这些数据与修复传递的对象指针有关,以便对所调用的函数正确。 In my example, when called Bar::addThemAll on a Qux object (which is perfectly valid because of inheritance) the pointer to the Qux object needs to be adjusted to point at the Bar sub-object before the function is called. 在我的示例中,当在Qux对象上调用Bar::addThemAll (由于继承是完全有效的)时,需要在调用函数之前将指向Qux对象的指针调整为指向Bar子对象。 So Qux::* s to member functions must have this adjustment encoded in them. 因此,成员函数的Qux::*必须在其中编码此调整。 After all, saying func = &Qux::addAllTheThings is perfectly valid, and if that function were called no pointer adjustment would be necessary. 毕竟,说func = &Qux::addAllTheThings是完全有效的,并且如果调用了该函数,则无需进行指针调整。 So the pointer adjustment is a part of the function pointer's value. 因此,指针调整是函数指针值的一部分。

And that's just an example. 那只是一个例子。 Compilers are permitted to implement member function pointers in any way they see fit (within certain constraints). 允许编译器以其认为合适的任何方式(在某些约束范围内)实现成员函数指针。 Many compilers (like the GNU C++ compiler on a 64-bit platform like I was using) will implement them in a way that do not permit any member function pointer to be treated as at all equivalent to normal function pointers. 许多编译器(例如我在使用的64位平台上的GNU C ++编译器)将以不允许将任何成员函数指针都视为等同于正常函数指针的方式来实现它们。

There are ways to deal with this. 有一些方法可以解决这个问题。 The swiss-army knife of dealing with member function pointers is the ::std::function template in C++11 or C++ TR1. 处理成员函数指针的瑞士军刀是C ++ 11或C ++ TR1中的::std::function模板。

An example: 一个例子:

 #include <functional>

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

funcob can point at absolutely anything that can be called like a function and needs a Qux * . funcob可以指向任何可以像函数一样调用且需要Qux * Member functions, global functions, static member functions, functors... funcob can point at it. 成员函数,全局函数,静态成员函数,函子... funcob可以指向它。

That example only works on a C++11 compiler though. 该示例仅适用于C ++ 11编译器。 But if your compiler is reasonably recent, but still not a C++11 compiler, this may work instead: 但是,如果您的编译器是相当新的,但仍不是C ++ 11编译器,则可以改用:

 #include <tr1/functional>

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

If worse comes to worse, you can use the Boost libraries, which is where this whole concept came from. 如果情况变得更糟,则可以使用Boost库,这是整个概念的来源。

But I would rethink your design. 但是我会重新考虑您的设计。 I suspect that you will get a lot more milage out of having a well thought out inheritance hierarchy and using virtual functions than you will out of whatever it is you're doing now. 我怀疑,如果您对继承层次结构进行了深思熟虑并使用了virtual函数,那么与现在所做的一切相比,您将得到更多的好处。 With an interpreter I would have a top level abstract 'expression' class that is an abstract class for anything that can be evaluated. 使用解释器,我将拥有一个顶级抽象“表达式”类,该类是可评估的所有内容的抽象类。 I would give it a virtual evaluate method. 我会给它一个虚拟的evaluate方法。 Then you can derive classes for different syntax elements like an addition expression a variable or a constant. 然后,您可以派生用于不同语法元素的类,例如加法表达式,变量或常量。 Each of them will overload the evaluate method for their specific case. 他们每个人都将针对其特定情况重载评估方法。 Then you can build up expression trees. 然后,您可以构建表达式树。

Not knowing details though, that's just a vague suggestion about your design. 虽然不知道细节,但这只是关于您设计的模糊建议。

Here is a clean solution. 这是一个干净的解决方案。 By means of a template wrap your member function into a static member function. 通过模板将您的成员函数包装为静态成员函数。 Then you can convert it to whatever pointer you want: 然后,您可以将其转换为所需的任何指针:

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

It seems that you need to convert a pointer to a member function to a void *. 看来您需要将指向成员函数的指针转换为void *。 I presume you want to give that pointer as a "user data" to some library function and then you will get back your pointer and want to use it on some given object. 我假设您想将该指针作为“用户数据”提供给某些库函数,然后您将取回指针并希望在某些给定对象上使用它。

If this is the case a reinterpret_cast<void *>(...) could be the right thing... I assume that the library receiving the pointer is not using it. 如果是这种情况,那么reinterpret_cast<void *>(...)可能是正确的事情...我假设接收指针的库未使用它。

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

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