假设我在运行时得到了一个对象和一个选择器,我打算安全地调用它,所以我定义了
#define objc_msgsend_va ((void (*)(id, SEL, ...))objc_msgsend)
#define Call_object(obj, sel, ...) objc_msgsend_va(obj, sel, ## __VA_ARGS__)
我可以安全地用Call_object宏替换任何方法调用,否则可能会导致某种崩溃。
这是为了在iOS设备上定义一个运行任意运行时方法的宏,我无法为每个方法显式转换为正确的函数类型,所以我使用了可变长度的参数。
主要考虑的是像这样使用宏的安全性。
不,这绝对不安全。它可以在很多常见情况下工作,但是va_args与将参数直接传递给函数不同。
拜托,拜托,请使用NSInvocation
。它为您解决了大约99%,同时更安全。可能存在它无法解决的边缘情况(例如,参数列表中的SSE / AVX向量),但它将超出您可能共同攻击的范围。
让我们通过架构来解决这个问题,看看这可能会起作用。
这些问题随处可见,没有真正的解决方案。
short
s和char
s也是如此。他们都会被大家化,这会在传递过程中造成很大的痛苦和痛苦。从技术上讲(与浮点数不同,因为它们有时会在特殊的FPU寄存器中传递),对于整数类型,您可以通过将它们包装在单个元素结构中来解决这个问题。这将阻止他们被提升。不过请不要这样做。我不打扰这个。如果您仍然需要针对这些macOS设备,请做两件事:
32位x86相当理智。没有复杂的注册参数传递,在我的头顶,我觉得这可能是相当理智。除了之前提到的问题,最重要的是x87 FPU引起的问题。避免漂浮,你可能不会在这里燃烧世界。
64位x86完全是另一个野兽。你将不得不学习很多关于编译器如何将寄存器分配给参数(和返回值!),当然还有新的SSE寄存器用于浮点。
我将把这些混为一谈,从这个角度来看没有重大差异。
像x86-64一样,如果你想100%安全,你将需要了解哪些寄存器在堆栈中的哪个位置,但是如果存储器召回,浮点传递在这里更简单。
Apple的ABI guide将是您的朋友。
这是我的知识最不稳定的地方,如果任何这些信息不正确,我道歉。
大多数函数调用都是通过寄存器完成的,因此我们之前的所有担忧仍然存在。现在有新的FPU寄存器,你必须处理浮点数,但如果你已经到了这一点,那就没有什么不可克服的了。