自定义objc_msgSend,与如果为参数为float的解决办法

问题:

I want to add scripting support for an Objective-C project using the objc runtime.

Now I face the problem, that I don't have a clue, how I should call an Objective-C method

which takes several named arguments.

So for example the following objective-c call

[object foo:bar];

could be called from C with:

objc_msgSend(object, sel_getUid("foo:"), bar);

But how would I do something similar for the method call:

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

=======================================================================
回答1.

       
       
objc_msgSend(object, sel_getUid("foo:bar:err:"), var, var2, errVar);

If one of the variables is a float, you need to use @Ken's method,

or cheat by a reinterpret-cast:

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

Also, if the selector returns a float, you may need to use objc_msgSend_fpret,

and if it returns a struct you must use objc_msgSend_stret.

If that is a call to superclass you need to use objc_msgSendSuper2.

回答2


The accepted answer is close, but it won't work properly for certain types.

For example, if the method is declared to take a

float as its second argument, this won't work.

To properly use objc_msgSend, you have to cast it to the the appropriate type.

For example, if your method is declared as

- (void)foo:(id)foo bar:(float)bar err:(NSError **)err

then you would need to do something like this:

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

Try the above case with just objc_msgSend, and log out the received arguments.

You won't see the correct values in the called

function. This unusual casting situation arises because objc_msgSend is not

intended to be called like a normal C function.

It is (and must be) implemented in assembly, and just

jumps to a target C function

after fiddling with a few registers.

In particular, there is no consistent way to refer to any

argument past the first

two from within objc_msgSend.

Another case where just calling objc_msgSend straight wouldn't

work is a method that

returns an NSRect, say, because

objc_msgSend is not used in that case, objc_msgSend_stret is.

In the underlying C function

for a method that returns an

NSRect, the first argument is actually a pointer to an out value NSRect,

and the function

itself actually returns void.

You must match this convention when calling because it's what the called

method will assume.

Further, the circumstances in which objc_msgSend_stret is used differ

between architectures.

There is also an objc_msgSend_fpret, which should be used for methods

that return certain

floating point types on certain

architectures.

Now, since you're trying to do a scripting bridge thing, you probably

cannot explicitly cast

every case you run across,

you want a general solution. All in all, this is not completely trivial,

and unfortunately your

code has to be specialized to

each architecture you wish to target (e.g. i386, x86_64, ppc).

Your best bet is probably to

see how PyObjC does it.

You'll also want to take a look at libffi. It's probably a good idea

to understand a little

bit more about how parameters

are passed in C, which you can read about in the Mac OS X ABI Guide. Last,

Greg Parker, who

works on the objc runtime,

has written a bunch of very nice posts on objc internals.

转载至:

http://stackoverflow.com/questions/2573805/using-objc-msgsend-to-call-a-objective-

c-function-with-named-arguments/2573949#2573949


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值