这与一系列面向对象的C贴子有关,但不同之处在于我不想要所有的功能,只有一个:
能够做到这一点:
struct foo {
int (*bar)(void);
char baz;
};
然后有一个反向引用。 C有一个名为cdecl的调用约定;基本上将参数推送到堆栈,有一个返回指针,然后跳转到某个地址。该地址的代码从堆栈中弹出参数并继续它的快乐方式。
这个调用约定略有不同,因为它增加了一个额外的参数,一个"这个"指针,含蓄地。
因为你可以很容易地在C中开始执行任意字节代码而且因为gcc支持内联汇编程序模板,所以这听起来像你可以制作一些宏,这样你就可以做类似的事情:
int bar(void) {
GETTHIS;
cThis->baz = 0;
}
int createFoo(struct Foo*pFoo) {
ASSIGN(pFoo, bar);
}
基本上,ASSIGN会做的是回避cdecl来模仿一个这样的样式约定,然后GETTHIS做的就是会计技巧的另一面。
我想知道是否:
仅此一点;真实的方便"我们所有人都同意这里的成年人"样式成员函数,简直太棒了。谢谢!
注意:
答案 0 :(得分:4)
第一次小修正:
C有一个名为cdecl的调用约定;基本上推动了争论 到堆栈,有一个返回指针,然后跳转到某个地址。该 该地址的代码将参数从堆栈中弹出并继续运行 快乐的方式。
被叫方不弹出堆栈中的参数。它会读取参数而不会从堆栈中弹出它们。而是由调用者清除堆栈。这是因为在cdecl约定中,被调用者不知道参数的确切数量。
现在,关于你的问题。没有严格定义的 thiscall 调用约定。更多信息here。
GCC-具体:
thiscall几乎与cdecl相同:调用函数清除 堆栈,参数以从右到左的顺序传递。该 差异是添加了这个指针,它被推到了上面 堆栈最后,好像它是函数中的第一个参数 原型
你无法隐藏额外的this
参数并在函数体内检索它,特别是因为this
是第一个函数参数。如果隐藏它 - 所有其他功能参数将被移位。相反,你可以(并且应该恕我直言)将它声明为第一个函数参数,并且你可以直接访问它,而不需要额外的技巧:
int bar(struct foo *cThis) {
cThis->baz = 0;
}
MSVC特异性:
...这个指针在ECX中传递,它是被清理的被调用者 堆栈,镜像C中使用的stdcall约定 编译器和Windows API函数。当函数使用变量时 参数的数量,它是清理堆栈的调用者(参见 的cdecl)。
在这里,您可以通过将ECX
寄存器的值复制到本地变量来实现。像这样:
#define GETTHIS \
struct foo *cThis; \
_asm { \
mov cThis, ecx \
};
但这很棘手,可能并不总是有效。原因是根据thiscall
/ stdcall
调用约定,ECX
寄存器保留用于函数,因此编译器可能生成覆盖{{1的值的代码注册。在您调用ECX
宏之前,甚至可能会发生这种情况。
答案 1 :(得分:4)
我的朋友最终得到了它:https://gist.github.com/1516195 ...需要指定功能arity并且仅限于x86_64 ......但是,这是一个非常好的妥协,使事情真的不显眼。
答案 2 :(得分:3)
不,C中没有对“thiscall”的支持,只适用于C ++。
这里也没有秘密技巧,只是一些语法糖。
写作时
class foo {
public:
int bar();
char baz;
};
编译器在概念上将其重写为
struct foo {
char baz;
};
int bar(struct foo* this);
然后当你做
foo F;
F.bar();
这被编译为等同于
struct foo F;
bar(&F);
这就是它的全部!
如果您想与Linus一起玩,您只需要手动执行此操作,因为他不信任您在输入g ++而不是gcc时不使用虚拟继承。< / p>