2

私は最近、NSLog(...)でこの奇妙な動作を追跡するために約30分を無駄にしました:

NSString *text = @"abc";
long long num = 123;
NSLog(@"num=%lld, text=%@",num,text); //(A)
NSLog(@"num=%d, text=%@",num,text); //(B)

行(A)は期待される「num = 123、text = abc」を出力しますが、行(B)は「num = 123、text = (null)」を出力します。

明らかに、withを印刷するのlong long%d間違いですが、なぜtextnullとして印刷されるのか説明できますか?

4

2 に答える 2

9

スタックのメモリアライメントを台無しにしました。x86プロセッサを搭載した最新のApple製品を使用していると思います。これらの仮定を考慮に入れると、スタックは両方の状況で次のようになります。

   | スタック| 最初| 2番目|
   + --------------------- + ------- + -------- +
   | 123 | | %d |
   + --------------------- +%lld + -------- +
   | 0 | | %@ |
   + --------------------- + ------- + -------- +
   | テキストへのポインタ| %@|無視|
   + --------------------- + ------- + -------- +  

最初の状況では、スタックに8バイト、次に4バイトを配置します。そして、NSLogはスタックから12バイト(の場合は8バイト、の場合は%lld4バイト%@)を取り戻すように指示されます。

2番目の状況では、NSLogに最初に4バイト(%d)を取るように指示します。変数の長さは8バイトで、保持する数が非常に少ないため、上位4バイトは0になります。NSLogがテキストを印刷しようとするとnil、スタックから取得されます。

メッセージの送信nilはObj-Cで有効であるため、NSLogは送信description:nilておそらく何も取得せずに出力します(null)。

結局、Objective-Cは追加されたCであるため、呼び出し元はこの混乱全体をクリーンアップします。

于 2009-08-04T18:50:56.760 に答える
1

varargsの実装方法は、システムによって異なります。ただし、引数のサイズが異なっていても、引数がバッファに連続して格納される可能性があります。したがって、long long int引数の最初の8バイト(それがのサイズであると仮定)は、long long intであり、次の4バイト(それがシステム上のポインターのサイズであると仮定)はNSStringポインターです。

int次に、関数にanを期待し、次にポインターを期待することを伝えると、最初の4バイトがint(のサイズであると仮定してint)、次の4バイトがポインターになることを期待します。システム上の特定のエンディアンと引数の配置により、最初の4バイトはlong long intたまたま数値の最下位バイトであるため、123が出力されます。次に、オブジェクトポインターの場合、次の4バイトが読み取られます。この場合は、数値の最上位バイトであり、すべて0であるため、nilポインターとして解釈されます。実際のポインタが読み取られることはありません。

于 2009-08-04T18:57:22.393 に答える