【问题标题】:How are the digits in ObjC method type encoding calculated?ObjC 方法类型编码中的数字是如何计算的?
【发布时间】:2012-07-17 17:06:35
【问题描述】:

Is 是对我之前的问题的跟进: What are the digits in an ObjC method type encoding string?

说有编码:

v24@0:4:8@12B16@20

这些数字是如何计算的? B 是一个字符,所以它应该只占用 1 个字节(而不是 4 个字节)。它与“对齐”有关吗? void的大小是多少?

按以下方式计算数字是否正确?在每个项目上询问 sizeof 并将结果四舍五入为 4 的倍数?第一个数字变成所有其他数字的总和?

【问题讨论】:

  • 您可能想在<objc/runtime/objc-typeencoding.m> 中闲逛。
  • 有趣。但这只是为了阅读代码(而不是为了生成代码),对吧?或者您可能打算展示如何使用代码...谢谢!
  • 是的,但它可以让您深入了解它们是如何组合在一起的。

标签: objective-c objective-c-runtime


【解决方案1】:

这些数字在 m68K 天中用于表示堆栈布局。也就是说,您可以从字面上解码方法签名,并且对于几乎所有类型,确切地知道堆栈帧内哪个偏移处的哪些字节您可以骗取/设置参数。

这很有效,因为 m68K 的 ABI 完全是 [IIRC -- 很长一段时间] 基于堆栈的参数/返回传递。没有任何东西被跨调用边界塞入寄存器。

然而,随着 Objective-C 被移植到其他平台,always-on-the-stack 不再是调用约定。参数和返回值通常在寄存器中传递。

因此,这些偏移量现在没有用了。同样,编译器使用的类型编码不再完整(因为它从来没有非常有用)并且会有一些类型不会被编码。更不用说对一些 C++ 模板化类型进行编码会产生方法类型编码字符串,其大小可能有很多千字节(我认为我遇到的记录大约是 30K 的类型信息)。

所以,不,使用sizeof() 生成数字是不正确的,因为它们实际上对所有事物都毫无意义。它们仍然存在的唯一原因是为了二进制兼容性;到处都有一些深奥的代码,它们仍然会解析类型编码字符串,期望会有随机数散布在这里和那里。

请注意,ObjC 运行时中存在 API 的痕迹,这仍然使人们相信可以动态编码/解码堆栈帧。确实不是,因为 C ABI 不保证参数寄存器将在面对优化时跨调用边界保留。你不得不去组装,事情变得非常非常快(>颤抖

【讨论】:

  • 我最近一直在琢磨这些东西,并开始怀疑这些数字是否真的意味着什么(特别是考虑到使用寄存器)。感谢您的确认!
  • 他们的根源在于 SmallTalk,真的。或者,具体来说,Objective-C 可以将 SmallTalk 的全部活力带入基于 C 编译的 ABI。它在 m68k 上工作,但被证明是无用的。因此在过去十年中转向越来越具体的打字;仍然允许运行时动态,但充分利用了编译器的类型安全性(以及分析器的模式分析)。
  • 我可以确认NSMethodSignature 期望signatureWithObjCTypes: 有一个非空类型字符串,并且摆弄具有不正确方法签名的NSInvocation 很可能会引发异常(例如, getArgument:atIndex: 依赖与方法签名的 numberOfArguments 相同的信息进行边界检查)。 @EcirHana
  • @Ecir:我想这取决于你用它做什么。 NSInvocation 似乎很高兴(在我不久前进行的 very 有限测试中)使用一个根本没有 no 数字的编码字符串,只要因为类型正确且数量正确。
  • 是的;您无法获得关于作为可变参数传递的 goop 的任何类型的元数据。而且,事实上,可变参数编码和非可变参数编码之间的 ABI 可以不同。这就是 ARC 编译器要求您将 objc_msgSend() 显式类型转换为特定强类型声明的部分原因(这也是为了履行 ARC 合同,这比标准 C ABI 更保守)。
【解决方案2】:

完整的编码字符串由ASTContext::getObjCEncodingForMethodDecl 方法构造(在clang 中),您可以在lib/AST/ASTContext.cpp 中找到该方法。

进行大小舍入的方法是ASTContext::getObjCEncodingTypeSize,在同一个文件中。它强制每个大小至少为int 的大小。在 Apple 当前的所有平台上,int 是 4 个字节。

【讨论】:

    【解决方案3】:

    堆栈帧大小和参数偏移量由编译器计算。这周我实际上正在尝试自己在 Clang 源中追踪这一点;它可能与CodeGenTypes::arrangeObjCMessageSendSignature 有关。 (看起来Rob just made我的生活轻松多了!)

    第一个数字是其他数字的总和,是的——它是参数占用的总空间。要获取代码中由 ObjC 类型编码表示的类型的大小,您应该使用NSGetSizeAndAlignment()。

    【讨论】:

      猜你喜欢
      • 2012-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多