为什么Objective-C编译器需要知道方法签名?

扎克·伊索尔

为什么Objective-C编译器需要在编译时知道将在对象上调用的方法的签名(如果可以将其推迟到运行时)(即动态绑定)?例如,如果我写[foo someMethod],为什么编译器必须知道someMethod的签名

罗布·纳皮尔

由于至少需要调用约定(使用ARC,有更多原因,但是调用约定始终是个问题)。

您可能已经被告知[foo someMethod]转换为函数调用:

objc_msgSend(foo, @selector(someMethod))

然而,这不是正是如此。取决于返回的内容(无论是否使用结果,返回的内容都很重要),它可能会转换为许多不同的函数调用。例如,如果它返回一个对象或一个整数,它将使用objc_msgSend,但是如果它返回一个结构(在ARM和Intel上),它将使用objc_msgSend_stret,并且如果它在Intel(但不是ARM)上返回一个浮点数),它将使用objc_msgSend_fpret这是因为在不同的处理器上,调用约定(如何设置堆栈和寄存器以及存储结果的位置)取决于结果而有所不同。

这也很重要,参数是什么以及参数有多少(可以从ObjC方法名称中推断出这些数字,除非它们是varargs ...对,您也必须处理varargs)。在某些处理器上,前几个参数可以放在寄存器中,而后几个参数可以放在堆栈中。如果您的函数采用varargs,则调用约定可能仍然不同。为了编译函数调用,所有这些都必须是已知的。

ObjC可以实现为更纯净的对象模型来避免所有这些情况(就像其他动态语言一样),但这将以性能(时空)为代价。考虑到动态调度的级别,ObjC可以使方法调用的价格出乎意料地便宜,并且可以轻松地使用纯C机器类型,但是这样做的代价是我们必须让编译器知道有关方法签名的更多细节。

顺便说一句,这可能(而且经常这样做)导致真正可怕的错误。如果您有两种方法:

- (MyPointObject *)point;

- (CGPoint)point;

也许在完全不同的文件中将它们定义为不同类上的方法。但是,如果编译器选择了错误的定义(例如,当您向发送消息时id),那么返回的结果-point可能是完全垃圾。这是一个非常非常难以发现的错误,它很难确定它何时发生(并且我已经发生过)。

有关更多背景知识,您可以欣赏Greg Parker的文章,其中介绍了objc_msgSend_stretobjc_msgSend_fpretMike Ash也对该主题进行了出色的介绍而且,如果您想深入研究这个兔子洞,您可以查看bbum对objc_msgSend的逐条说明调查在ARC之前,它已经过时了,仅涵盖x86_64(因为每个体系结构都需要自己的实现),但是仍然具有很高的教育意义,建议使用。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

为什么需要C ++编译器来编译Rust?

来自分类Dev

为什么在编译时需要知道对象的内存配置文件以进行堆栈放置?

来自分类Dev

为什么C编程需要编译器而shell脚本不需要?

来自分类Dev

为什么路由器需要知道调制解调器的静态IP地址?

来自分类Dev

为什么这个Objective-C ++程序不能编译?

来自分类Dev

Objective-C为什么需要__NSGlobalBlock__

来自分类Dev

为什么教义需要知道列信息?

来自分类Dev

为什么C和C ++编译器从不强制执行函数签名中的数组长度?

来自分类Dev

Objective-C:编译器警告,意外覆盖方法

来自分类Dev

为什么C#编译器在静态方法调用实例方法的地方不会出错?

来自分类Dev

为什么Objective-C数组参数不使用冒号?

来自分类Dev

为什么Objective-C异常不友好?

来自分类Dev

为什么CGBitmapInfo删除了Objective-C中的kCGBitmapByteOrderDefault?

来自分类Dev

Objective C故事板为什么ParentViewController为零

来自分类Dev

在 Objective-C 中,为什么编译器会关心两个完全不同的视图控制器类中的同名变量?

来自分类Dev

为什么编译器找不到超类的方法?

来自分类Dev

为什么编译器选择了错误的方法重载?

来自分类Dev

CMake为什么要检查C ++编译器?

来自分类Dev

为什么C ++编译器的常数折叠效果更好?

来自分类Dev

为什么C#编译器允许空枚举?

来自分类Dev

为什么C#编译器无法优化简单的异步/等待方法

来自分类Dev

为什么C#编译器将il代码留给条件方法?

来自分类Dev

为什么C#编译器说字符串没有`Contains`方法

来自分类Java

为什么编译器需要.java后缀,但解释器不需要.class后缀?

来自分类Dev

为什么编译器对功能签名要求如此严格的匹配?

来自分类Dev

即使C ++编译器无法编译,为什么C编译器仍可以编译此代码?

来自分类Dev

为什么编译器跳过for循环?

来自分类Dev

为什么编译器左移0?

来自分类Dev

为什么编译器(例如javac)必须知道对象的大小?

Related 相关文章

  1. 1

    为什么需要C ++编译器来编译Rust?

  2. 2

    为什么在编译时需要知道对象的内存配置文件以进行堆栈放置?

  3. 3

    为什么C编程需要编译器而shell脚本不需要?

  4. 4

    为什么路由器需要知道调制解调器的静态IP地址?

  5. 5

    为什么这个Objective-C ++程序不能编译?

  6. 6

    Objective-C为什么需要__NSGlobalBlock__

  7. 7

    为什么教义需要知道列信息?

  8. 8

    为什么C和C ++编译器从不强制执行函数签名中的数组长度?

  9. 9

    Objective-C:编译器警告,意外覆盖方法

  10. 10

    为什么C#编译器在静态方法调用实例方法的地方不会出错?

  11. 11

    为什么Objective-C数组参数不使用冒号?

  12. 12

    为什么Objective-C异常不友好?

  13. 13

    为什么CGBitmapInfo删除了Objective-C中的kCGBitmapByteOrderDefault?

  14. 14

    Objective C故事板为什么ParentViewController为零

  15. 15

    在 Objective-C 中,为什么编译器会关心两个完全不同的视图控制器类中的同名变量?

  16. 16

    为什么编译器找不到超类的方法?

  17. 17

    为什么编译器选择了错误的方法重载?

  18. 18

    CMake为什么要检查C ++编译器?

  19. 19

    为什么C ++编译器的常数折叠效果更好?

  20. 20

    为什么C#编译器允许空枚举?

  21. 21

    为什么C#编译器无法优化简单的异步/等待方法

  22. 22

    为什么C#编译器将il代码留给条件方法?

  23. 23

    为什么C#编译器说字符串没有`Contains`方法

  24. 24

    为什么编译器需要.java后缀,但解释器不需要.class后缀?

  25. 25

    为什么编译器对功能签名要求如此严格的匹配?

  26. 26

    即使C ++编译器无法编译,为什么C编译器仍可以编译此代码?

  27. 27

    为什么编译器跳过for循环?

  28. 28

    为什么编译器左移0?

  29. 29

    为什么编译器(例如javac)必须知道对象的大小?

热门标签

归档