12

私の前の質問へのフォローアップです: ObjC メソッド型エンコーディング文字列の数字は何ですか?

エンコーディングがあるとします:

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

これらの数値はどのように計算されますか? Bは char であるため、1 バイト (4 バイトではなく) を占める必要があります。「合わせ」とか関係あるの?の大きさはvoid

次のように数値を計算するのは正しいですか?すべての項目について質問sizeofし、結果を 4 の倍数に切り上げますか? そして、最初の数は他のすべての数の合計になりますか?

4

3 に答える 3

18

番号は、スタックレイアウトを示すためにm68K日に使用されました。つまり、メソッドシグネチャを文字通りデコードし、ほぼすべてのタイプについて、引数を取得/設定するためにスタックフレーム内のどのオフセットでどのバイトを実行できるかを正確に知ることができます。

これが機能したのは、m68KのABIが完全に[IIRC-長い間]スタックベースの引数/リターンの受け渡しであったためです。呼び出しの境界を越えてレジスターに押し込まれるものは何もありませんでした。

ただし、Objective-Cが他のプラットフォームに移植されたため、always-on-the-stackはもはや呼び出し規約ではありませんでした。引数と戻り値は、多くの場合、レジスターで渡されます。

したがって、これらのオフセットは現在は役に立たない。同様に、コンパイラーによって使用される型エンコードは完全ではなくなり(ひどく有用ではなかったため)、エンコードされない型が存在するようになります。一部のC++テンプレート化型をエンコードすると、サイズが数キロバイトになる可能性のあるメソッド型エンコード文字列が生成されることは言うまでもありません(私が遭遇したレコードは約30Kの型情報だったと思います)。

ですから、いいえ、数字を生成するために使用するのは正しくありませんsizeof()。なぜなら、それらは事実上すべてにとって無意味だからです。それらがまだ存在する唯一の理由は、バイナリ互換性のためです。あちこちに乱数が散らばっていることを期待して、型エンコーディング文字列を解析する難解なコードがちらほらあります。

ObjCランタイムにはAPIの痕跡があり、スタックフレームをその場でエンコード/デコードできる可能性があると信じ込ませていることに注意してください。C ABIは、最適化に直面して引数レジスタが呼び出し境界を越えて保持されることを保証しないため、実際にはそうではありません。あなたは組み立てに立ち寄らなければならないでしょう、そして物事は本当に本当に速く醜くなります(>震え<)。

于 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。(ロブは私の人生をずっと楽にしてくれました!)

最初の数値は、他の数値の合計です。そうです。これは、引数が占める合計スペースです。コード内の ObjC 型エンコーディングによって表される型のサイズを取得するには、 を使用する必要がありますNSGetSizeAndAlignment()

于 2012-07-17T17:33:23.543 に答える