假设我在运行时有一个对象及其选择器之一,我打算安全地调用它,所以我定义了
#define objc_msgsend_va ((void (*)(id, SEL, ...))objc_msgsend)
#define Call_object(obj, sel, ...) objc_msgsend_va(obj, sel, ## __VA_ARGS__)
我可以用Call_object宏安全地替换任何方法调用,否则可能导致某种崩溃。
这是为了定义一个宏以在iOS设备上运行任意运行时方法,我无法显式转换每种方法的正确函数类型,因此我使用了变长参数。
主要考虑因素是使用此类宏的安全性。
答案 0 :(得分:3)
不是,这绝对是不安全的。它可以在很多常见情况下工作,但是va_args与将参数直接传递给函数并不相同。
请,请继续使用NSInvocation
。它可以为您解决大约99%的问题,同时更加安全。可能存在一些无法解决的极端情况(例如,参数列表中的SSE / AVX向量),但是它比您可能会一起破解的东西要跨越式发展。
让我们按体系结构对其进行分解,然后查看 可能在哪些方面起作用。
这些问题将无处不在,没有实际的解决方案。
作为va_args传递时,浮点数始终会加倍。参见the C standard,第6.5.2.2节
short
和char
的情况相同。它们也会全部变大,通过时会引起很多痛苦。从技术上讲(与浮点数不同,因为浮点数有时会通过特殊的FPU寄存器传递),对于整数类型,可以通过将它们包装在单个元素结构中来解决。这将阻止他们被提升。不过请不要这样做。
联合,或复杂的结构。还需要其他对齐方式和填充方式以及注意事项。如果您想要一个稳定的解决方案,则必须深入研究编译器代码。
如果您开始触摸返回值,事情将变得更加复杂,并且您需要了解架构何时将结构打包到寄存器中以获取返回值(请参见a lot {{ 3}}先前的讨论)。
我对此并不打扰。如果仍然需要定位这些macOS设备,则有两件事:
我对你很不好。
您可能拥有比我更多的背景信息。祝你好运,加油!
32位 x86非常理智。我的头顶上没有复杂的寄存器参数通过,我觉得这可能很理智。除了前面提到的问题外,最大的问题是由x87 FPU引起的问题。避免漂浮,否则您可能不会在这里燃烧世界。
64位 x86完全是另一种野兽。您将需要学习很多有关编译器如何将寄存器分配给参数(并返回值!)的知识,当然还有新的SSE浮点寄存器。
我要把它们放在一起,从这个角度来看并没有太大的区别。
像x86-64一样,如果要确保100%安全,则必须了解有关哪些寄存器在堆栈中的位置,但是如果内存被调用,则此处的浮点传递会更简单。
这里的苹果of是您的朋友。
这是我最不了解的地方,对于其中任何信息不正确,我深表歉意。
大多数函数调用完全通过寄存器执行,因此我们以前的所有担忧仍然存在。现在有新的FPU寄存器需要处理浮点数,但是如果您要达到这一点,那就没有什么不可逾越的了。