12

是我之前问题的后续: ObjC 方法类型编码字符串中的数字是什么?

假设有一个编码:

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

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

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

4

3 回答 3

18

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

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

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

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

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

Note that there are vestiges of API in the ObjC runtime that still lead one to believe that it might be possible to encode/decode stack frames on the fly. It really isn't as the C ABI doesn't guarantee that argument registers will be preserved across call boundaries in the face of optimization. You'd have to drop to assembly and things get ugly really really fast (>shudder<).

于 2012-07-17T17:42:34.473 回答
9

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

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

于 2012-07-17T17:24:42.707 回答
1

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

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

于 2012-07-17T17:33:23.543 回答