NSLog(…)不適切なフォーマット指定子は他の変数に影響しますか?
-
22-07-2019 - |
質問
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)"を印刷します。
明らかに、%d
で long long
を印刷するのは間違いですが、誰かが text
を次のように印刷する理由を説明できますnull?
解決
スタックのメモリの配置が台無しになりました。 x86プロセッサを搭載した最新のApple製品を使用していることを前提としています。これらの仮定を考慮に入れると、スタックは両方の状況で次のようになります。
| stack | first | second | +---------------------+-------+--------+ | 123 | | %d | +---------------------+ %lld +--------+ | 0 | | %@ | +---------------------+-------+--------+ | pointer to text | %@ |ignored | +---------------------+-------+--------+
最初の状況では、スタックに8バイト、次に4バイトをスタックします。 NSLogはスタックから12バイト(%lld
の場合は8バイト、%@
の場合は4バイト)を返すように指示されています。
2番目の状況では、NSLogに最初に4バイト(%d
)を使用するよう指示します。変数の長さは8バイトで、小さい数値を保持するため、その上位4バイトは0になります。NSLogがテキストを印刷しようとすると、スタックから nil
が使用されます。
Obj-Cでは nil
へのメッセージ送信が有効なので、NSLogは description:
を nil
に送信するだけで、おそらく何も取得せずに印刷します( null)。
Objective-Cは追加されたCであるため、呼び出し側はこの混乱をすべてクリーンアップします。
他のヒント
可変引数の実装方法はシステムに依存します。ただし、引数のサイズが異なる場合でも、引数はバッファに連続して格納される可能性があります。そのため、引数の最初の8バイト( long long int
のサイズであると仮定)は long long int
であり、次の4バイトは(それがシステム上のポインター)は NSString
ポインターです。
次に、関数に int
を期待し、次にポインターを期待すると、最初の4バイトが int
であると期待します(サイズが int
)および次の4バイトがポインターになります。システム上の特定のエンディアンと引数の配置のため、 long long int
の最初の4バイトはたまたま数字の最下位バイトなので、123を出力します。 、次の4バイトを読み取ります。この場合、これは数値の最上位バイトであり、すべて0であるため、 nil
ポインターとして解釈されます。実際のポインターは読み取られません。