2

"Member function" is the most stubborn thing. Simply I cannot convert them into *void values. I've done some methods which can solve this; however, the only thing I annoyed: I have to create a new definition for every set of argument types. So the fastest method to achieve the goal :

struct FOO{

    void ONE_PARAM(int){}
    void TWO_PARAM(int, int){}
    void THREE_PARAM(int, int, int){}
    void FOUR_PARAM(int, int, int, int){}
};

Firstly, calling a structure function member by assembly :

__asm mov ecx, ADDRESS_OF_STRUCTURE
__asm push //parameters
__asm call ADDRESS_OF_MEMBER_FUNCTION

Longest : Template...

template <class F,void (F::*Function)(int)>   //Note : Only for FOO::ONE_PARAM
void * GetFunctionAddress() {

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

    address_data.func = Function;  
    return address_data.function_address; 
}

Shorter method : Define a function pointer to member function

void *function_address;
///////////////////////////////////////////////
void(FOO::*address_ONE_PARAM)(int) = FOO::ONE_PARAM;
void(FOO::*address_TWO_PARAM)(int, int) = FOO::TWO_PARAM;
void(FOO::*address_THREE_PARAM)(int, int, int) = FOO::THREE_PARAM;
void(FOO::*address_FOUR_PARAM)(int, int, int, int) = FOO::FOUR_PARAM;

__asm mov eax, address_ONE_PARAM //OK
__asm mov function_address, eax

__asm mov eax, address_TWO_PARAM //OK
__asm mov function_address, eax

__asm mov eax, address_THREE_PARAM //OK
__asm mov function_address, eax

__asm mov eax, address_FOUR_PARAM //OK
__asm mov function_address, eax

But it's still too long.

The most convenient method : Using directly standard function : sprintf

I discovered __thiscall functions also can be pushed as "..." parameters and I have checked it carefully by function printf. It is simple, and you don't need to define again its whole set of argument types to accept the pointer. And the code :

unsigned int address;
char buffer[12];
///////////////////////////////////////////////
sprintf(buffer, "0x%X", FOO::ONE_PARAM);
address = strtol(buffer,NULL,16);

sprintf(buffer, "0x%X", FOO::TWO_PARAM);
address = strtol(buffer,NULL,16);

sprintf(buffer, "0x%X", FOO::THREE_PARAM);
address = strtol(buffer,NULL,16);

sprintf(buffer, "0x%X", FOO::FOUR_PARAM);
address = strtol(buffer,NULL,16);

As you can see this method is much shorter and also it's very convenient. I don't need to insert assembly code, the code looks better but on the other hand, I am worrying about speed. Can the code be compressed more? Suppose two commands now it only requires a single command to work, is this possible?

Matt
  • 22,721
  • 17
  • 71
  • 112
  • By "function member" do you mean "member function"? – Kerrek SB Jan 30 '13 at 09:51
  • Why do you need to convert the function address to void*? – Michael Aaron Safyan Jan 30 '13 at 09:51
  • 2
    Member functions are not functions. (E.g. you cannot *call* a member function.) It is unreasonable to even *expect* that they should have an address in the classic sense. – Kerrek SB Jan 30 '13 at 09:53
  • I am building up a function library, and I will use its database to call a function by assembly... And "member function" : I will pick a proper structure, move its address to ecx and then call it with function member address. See http://en.wikipedia.org/wiki/X86_calling_conventions –  Jan 30 '13 at 09:54
  • @KerrekSB [Why not?](http://stackoverflow.com/questions/990625/c-function-pointer-class-member-to-non-static-member-function) –  Jan 30 '13 at 09:55
  • Why don't you just make a bunch of non-member functions that forward to the member functions, and take the address of those? – Mankarse Jan 30 '13 at 09:55
  • 3
    Use std::function from C++11. – Spook Jan 30 '13 at 09:56
  • @Mankarse That would, at least, give him a hint of why it cannot work. – James Kanze Jan 30 '13 at 09:58
  • None of the solutions you propose will actually give you anything usable. – James Kanze Jan 30 '13 at 09:58
  • It does not throw any compiling error. I have re-tested again my results by all methods and the function **printf**. And no errors have been found. –  Jan 30 '13 at 10:03
  • @xersi: Just testing alone cannot guarantee the correctness of your code. You can't convert pointers to member functions to `void*` because [pointers to member functions can have a size bigger than `sizeof(void*)`](http://blogs.msdn.com/b/oldnewthing/archive/2004/02/09/70002.aspx). That fact alone makes stuffing pointers to member functions into `void*` a non-starter. – In silico Jan 30 '13 at 10:07
  • With that I am going to do some research. For example I think **virtual function** is just a normal function object, only it's partly related to the base function. EDIT : I know the size, but I have an evidence which can partly prove why my algorithm is correct (not sure) –  Jan 30 '13 at 10:10
  • @xersi: I'm sorry to say but you're missing the point. You can't just stuff any arbitrary member function pointer into a `void*` because there's no guarantee that the size of a member function pointer is less than or equal to `sizeof(void*)`. No such guarantee exists in order to allow compilers to generate useful member function pointers for all possible cases. – In silico Jan 30 '13 at 10:14
  • But my compiler does. Weird? I can freely call a member function with `void*` address by assembly and it runs properly without any error. :) –  Jan 30 '13 at 10:17
  • 1
    @xersi Irrelevant implementation details. – Cat Plus Plus Jan 30 '13 at 10:24
  • 1
    @xersi it doesn't mean it isn't UB – Bartek Banachewicz Jan 30 '13 at 10:25
  • Well, hard to explain. I'll check again. And check whether 4-byte pointer or 8-byte pointer is correct or not... –  Jan 30 '13 at 10:33
  • @xersi You "check it" by reading the standard, not doing weird tricks in code. Implementation is not relevant here for anything – Cat Plus Plus Jan 30 '13 at 10:35
  • @Xersi You haven't actually tried to use the results of your conversion, at least not for anything non-trivial. The conversions are all more or less legal, _but_ you've lost information, and cannot use the results in any way. – James Kanze Jan 30 '13 at 12:04
  • @xersi What compiler are you using. For g++, the sizes are 4 and 8. For VC++, 4 and 16. (With VC++, of course, you have to use the option `/vmg`. Otherwise, pointers to member functions don't work. – James Kanze Jan 30 '13 at 12:11
  • @xersi And I can guarantee that the results of your conversions _don't_ work with g++ or VC++. If you are using one of these compilers, and they seem to work, you just haven't tested it sufficiently. – James Kanze Jan 30 '13 at 12:13

2 Answers2

5

Unless your compiler is broken, you can't directly convert any function pointer, member of not, to void*. On systems where non-member function pointers have the same size and format as non-member data pointers (required by Posix), you can do some fancy type punning:

void (*fp)();
void * p = *reinterpret_cast<void**>( &fp );

This is undefined behavior according to the C++ standard, but will work on most von Neumann machines with linear addressing. (It is likely to do strange things on Harvard architectures, or machines with non-linear addressing.)

This only works when the types (original and target) have exactly the same size and format. Pointers to member functions require additional information, which means that they almost never have the same size and format as normal function pointers, let alone data pointers.

I might add that none of the methods you describe actually work, in the sense that you can use the results in any way.

swegi
  • 4,046
  • 1
  • 26
  • 45
James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • 1
    So basically POSIX defines an UB in C++? –  Jan 30 '13 at 09:58
  • 2
    @H2CO3: It does. For example `dlsym` returns `void*` despite the fact that it returns the address of a function. – Mankarse Jan 30 '13 at 10:02
  • It is a regular function object. I am taking about function member (structure). –  Jan 30 '13 at 10:05
  • @Mankarse I know that, but I always thought it was UB even under POSIX. –  Jan 30 '13 at 10:05
  • @H2CO3 In some cases, yes. In this case, all it's doing is restricting the possibilities of implementation defined behavior. – James Kanze Jan 30 '13 at 11:59
  • @H2CO3 Something like `(void (*)())dlsym(...)` is illegal, even in Posix, and a compliant C or C++ compiler is required to emit a diagnostic. The example of `dlsym` use in the Posix standard is `*(void **)(&fptr) = dlsym(handle, "my_function");`, which is well defined _if_ `void*` and `int (*)(int)` (the type of `fptr`) have the same size and representation. Which Posix requires. – James Kanze Jan 30 '13 at 12:02
  • @H2CO3: Why not -- UB means anything can happen, including well-defined behaviour under some additional guarantees. Posix chooses to provide such guarantees for this behaviour. It's legal under C++ to behave well. – Kerrek SB Jan 30 '13 at 13:10
0

A pointer to member function can be cast to another pointer to member function type (per 5.2.10p10). So, instead of void *, use void (*X::)() for some placeholder user-defined type X:

struct X;
typedef void (*X::mem_fun_ptr_t)();

mem_fun_ptr_t mem_fun_ptr = reinterpret_cast<mem_fun_ptr_t>(&FOO::ONE_PARAM);
mem_fun_ptr_t mem_fun_ptr = reinterpret_cast<mem_fun_ptr_t>(&FOO::TWO_PARAM);
mem_fun_ptr_t mem_fun_ptr = reinterpret_cast<mem_fun_ptr_t>(&FOO::THREE_PARAM);
mem_fun_ptr_t mem_fun_ptr = reinterpret_cast<mem_fun_ptr_t>(&FOO::FOUR_PARAM);

Whether this is useful depends on what you're planning to do with the cast pointer; you can't call it without knowing the original type to cast it back to.

ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • @ ecatmur - Is it conflict if I want to merge all database (**all standard functions** with all member functions from different classes & structures)? I have to use `void*`, `unsigned int`, or anything else? –  Jan 30 '13 at 10:25
  • @xersi what problem are you actually trying to solve? Why do you want to hold member function pointers in the same type as a function pointer? – ecatmur Jan 30 '13 at 14:28
  • Just I am going to make a generic structure like this `struct {void * address; DWORD code; unsigned struct_ID; PARAMETER_INFO param_info;};` - It holds the address of a function in general, and that's why I want to keep `void*` or `unsigned int`. –  Jan 30 '13 at 14:35
  • @xersi there's no such thing as the address of a function in general. What are you planning to do with `address`: call it, use it as a tag, use it as a key? – ecatmur Jan 30 '13 at 15:04