This is relating to the flurry of object-oriented C postings, but differs in that I don't want all the features, just one:
An ability to do this:
struct foo {
int (*bar)(void);
char baz;
};
An then have the back-reference. C has a calling convention called cdecl; basically pushes arguments on to the stack, has a return pointer, then jumps to some address. The code at that address pops arguments off the stack and goes on its merry way.
The thiscall convention is slightly different in that it adds one extra argument, a "this" pointer, implicitly.
Since you can start executing arbitrary byte code in C quite easily AND since gcc supports inline assembler templating, this sounds like you could just make some macro so that you could do something like:
int bar(void) {
GETTHIS;
cThis->baz = 0;
}
int createFoo(struct Foo*pFoo) {
ASSIGN(pFoo, bar);
}
Basically what ASSIGN would do is sidestep cdecl in someway to emulate a thiscall style convention and then what GETTHIS would do is the other side of the accounting trick.
I was wondering if:
Just this alone; the convenience of true "We're all consenting adults here" style member functions, would be simply awesome. Thanks!
Notes:
My friend eventually got it: https://gist.github.com/1516195 ... requires specifying function arity and is limited to x86_64 ... but yes, it's a pretty nice compromise that makes things really unobtrusive.
First little correction:
C has a calling convention called cdecl; basically pushes arguments on to the stack, has a return pointer, then jumps to some address. The code at that address pops arguments off the stack and goes on its merry way.
The callee does not pop the arguments from the stack. It reads the parameters without popping them from the stack. Instead the stack is cleared by the caller. This is so because in cdecl convention the callee doesn't know the exact number of parameters.
Now, regarding your question. There's no strictly defined thiscall calling convention. More info here.
Gcc-specific:
thiscall is almost identical to cdecl: the calling function cleans the stack, and the parameters are passed in right-to-left order. The difference is the addition of the this pointer, which is pushed onto the stack last, as if it were the first parameter in the function prototype
You'll not be able to do your trick with concealing the extra this
argument and retrieving it inside the function body, specifically because this
is the first function argument. If you conceal it - all the other function parameters will be shifted. Instead you may (and should IMHO) declare it as the first function argument, and you'll have the direct access to it, without the need in extra tricks:
int bar(struct foo *cThis) {
cThis->baz = 0;
}
Msvc-specific:
... the this pointer is passed in ECX and it is the callee that cleans the stack, mirroring the stdcall convention used in C for this compiler and in Windows API functions. When functions use a variable number of arguments, it is the caller that cleans the stack (cf. cdecl).
Here you may do your trick by copying the value of the ECX
register into your local variable. Something like this:
#define GETTHIS \
struct foo *cThis; \
_asm { \
mov cThis, ecx \
};
This however is tricky and may not always work. The reason for this is that according to the thiscall
/stdcall
calling conventions the ECX
register is reserved for function use, hence the compiler may generated the code that overwrites the value of ECX
register. This may even happen before you invoke the GETTHIS
macro.
No, there is no support for "thiscall" in C, that is just for C++.
There is no secret trick here either, just some syntactic sugar.
When you write
class foo {
public:
int bar();
char baz;
};
the compiler conceptually rewrites this as
struct foo {
char baz;
};
int bar(struct foo* this);
and then when you do
foo F;
F.bar();
this is compiled as the equivalent of
struct foo F;
bar(&F);
That's all there is to it!
If you want to play with Linus, you will just have to do this by hand because he doesn't trust you not to use virtual inheritance as soon as you type g++ instead of gcc.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With