Objective c 使用objc_msgSend调用带有命名参数的目标C函数

Objective c 使用objc_msgSend调用带有命名参数的目标C函数,objective-c,cocoa,reflection,Objective C,Cocoa,Reflection,我想使用objc运行时为Objective-C项目添加脚本支持。现在我面临的问题是,我不知道该如何调用一个接受多个命名参数的Objective-C方法 例如,下面的objective-c调用 [object foo:bar]; 可以使用以下命令从C调用: objc_msgSend(object, sel_getUid("foo:"), bar); 但是我如何对方法调用执行类似的操作: [object foo:var bar:var2 err:errVar]; ? 最佳马库斯酒店 objc_

我想使用objc运行时为Objective-C项目添加脚本支持。现在我面临的问题是,我不知道该如何调用一个接受多个命名参数的Objective-C方法

例如,下面的objective-c调用

[object foo:bar];
可以使用以下命令从C调用:

objc_msgSend(object, sel_getUid("foo:"), bar);
但是我如何对方法调用执行类似的操作:

[object foo:var bar:var2 err:errVar];
?

最佳马库斯酒店

objc_msgSend(object, sel_getUid("foo:bar:err:"), var, var2, errVar);
如果其中一个变量是
float
,则需要使用的方法,或通过重新解释强制转换进行欺骗:

objc_msgSend(..., *(int*)&var, ...)

此外,如果选择器返回浮点,则可能需要使用
objc\u msgSend\u fpret
,如果它返回结构,则必须使用
objc\u msgSend\u stretc
。如果这是对超类的调用,则需要使用
objc_msgSendSuper2

objc_msgSend(obj,@selector(foo:bar:err:)、var、var2和errVar)

接受的答案很接近,但对于某些类型来说,它无法正常工作。例如,如果该方法被声明为将float作为其第二个参数,那么这将不起作用

要正确使用objc_msgSend,必须将其强制转换为适当的类型。例如,如果您的方法声明为

- (void)foo:(id)foo bar:(float)bar err:(NSError **)err
然后,您需要执行以下操作:

void (*objc_msgSendTyped)(id self, SEL _cmd, id foo, float bar, NSError**error) = (void*)objc_msgSend;
objc_msgSendTyped(self, @selector(foo:bar:err:), foo, bar, error);
使用objc_msgSend尝试上述情况,并注销收到的参数。在被调用的函数中看不到正确的值。出现这种不寻常的强制转换情况是因为objc_msgSend不打算像普通的C函数那样被调用。它是(而且必须)在汇编中实现的,在处理了几个寄存器之后,它就跳转到目标C函数。特别是,在objc_msgSend中,没有一致的方法引用任何超过前两个参数的参数

直接调用objc_msgSend不起作用的另一种情况是返回NSRect的方法,例如,因为在这种情况下不使用objc_msgSend,所以objc_msgSend_stret是。在返回NSRect的方法的基础C函数中,第一个参数实际上是指向输出值NSRect的指针,函数本身实际上返回void。调用时必须符合此约定,因为被调用的方法将采用此约定。此外,不同体系结构之间使用objc_msgSend_stret的情况不同。还有一个objc_msgSend_fpret,应该用于在某些体系结构上返回某些浮点类型的方法


现在,由于您正在尝试编写脚本桥接器,您可能无法显式地强制转换遇到的每个案例,您需要一个通用的解决方案。总而言之,这并不是一件小事,不幸的是,您的代码必须针对您希望针对的每个体系结构(例如i386、x86_64、ppc)进行专门化。你最好的办法可能是看看它是如何做到的。你还需要看一看。了解更多关于参数在C中如何传递的信息可能是一个好主意,您可以在。最后,在objc运行时工作的Greg Parker编写了objc内部代码。

这很接近,但对于采用特定类型的方法,将不会像预期的那样工作。例如,假设该方法声明为其中一个参数使用浮点。objc_msgSend声明为varargs函数,传递给它的任何浮点值都将提升为double。然后,objc_msgSend的impl将跳转到期望浮点的方法,它将不起作用。详细情况见我的答案。肯完全正确;vararg处理ABI和float/double处理ABI可能非常反常,具体取决于CPU。关于编辑:并非所有体系结构上的所有结构返回都使用objc\u msgSend\u stret。它因架构和struct.annnd中的内容而异,reinterpret cast的工作也不可靠。;-)我认为关键是要转换为int,因为int和float的大小相同?不幸的是,int和float在所有体系结构上的传递方式并不相同,即使它们具有相同的大小。铸造浮动没有好处,因为它只是被提升到双倍。真的,您需要强制转换函数指针。(上面的重新解释强制转换也是一个严格的别名冲突。好了,我完成了!很抱歉竖琴!)由于Ken描述的原因无法工作。。。您需要创建一个特定类型的函数指针。Objecrtive-C没有命名参数。它的参数与方法名交错。(命名参数意味着删除名称是一种选择,但事实并非如此)。鉴于markus只是想创建一个用于脚本访问的通用桥,而不是一个高性能的c级桥,他难道不能像这里这样使用use NSINVOATION:标准c中不允许在函数指针类型和
void*
之间进行强制转换吗