はじめに
私は、hogeというNSIntegerの変数の値をログ出力する時に、
NSInteger hoge = 100;
NSLog(@"output hoge = %ld", (long)hoge);
といったコードを書いていました。
NSStringでNSIntegerの変数の値を扱う場合は、
NSInteger hoge = 100;
NSString *hogeString = [NSString stringWithFormat:@"%ld", (long)hoge];
みたいな感じですね。
このlongにキャストしているコードについて、
NSNumberを使う or 書式指定子を**%zd**にしましょうと先日教わりました。
(本記事では、NSNumberについては特に触れません。)
そもそもなぜNSIntegerはlongにキャストしなければいけなかったのかなーということを含めて整理します。
NSIntegerの値をログ出力してみる
1.NSIntegerの値を指定子%dでログ出力
NSInteger hoge = 100;
NSLog(@"output hoge = %d", hoge);
caseA. iPhone5以前の端末(and iPhone5c)
→怒られない。
指定子%dを使用した場合は、
32bit端末では怒られないが、64bit端末では怒られる
ということですね。
2.NSIntegerの値を指定子%ldでログ出力
NSInteger hoge = 100;
NSLog(@"output hoge = %ld", hoge);
caseA. iPhone5以前の端末(and iPhone5c)
→怒られる。
指定子%ldを使用した場合は、
32bit端末では怒られるが、64bit端末では怒られない
ということですね。
1.の%dを使用した場合と2.の%ldを使用した場合ともに
「引数にNSIntegerを使用すべきでない。明示的にlongにキャストすべきだよ。」
というような警告が出ています。
警告の通りlongにキャストしてあげれば、32bit端末でも64bit端末でも怒られません。
警告の意味を探る
警告の意味を探るためにNSIntegerがどんなヤツなのか覗いてみました。
32bitの場合は、
typedef int NSInteger;
typedef unsigned int NSUInteger;
64bitの場合は、
typedef long NSInteger;
typedef unsigned long NSUInteger;
という定義でした。
先ほど確認した警告は、
32bit端末, 64bit端末ではNSIntegerの定義が違うため発生していた
ということですね。
長たらしくて現実的に使うことは無いですが、
以下のように書いてみたら32bit端末,64bit端末ともに
警告無く、ログ出力できました。
NSInteger hoge = 100;
# ifdef __LP64__
NSLog(@"[64bit] output hoge = %ld", hoge);
# else
NSLog(@"[32bit] output hoge = %d", hoge);
# endif
書式%zdで32bit, 64bit両方に対応
警告の原因はわかりました。
続いて、明示的にキャストしなくても32bit, 64bit両方に対応できるという**%zd**とは何者なのか整理してみます。
%zdは、
指定子%d(符号付き32bit整数)に
長さ修飾子z(size_tまたはこれに類する符号つき整数であることを指定)
をくっつけたものです。
(文字列操作プログラミングガイドのp16~ あたりを参考にしました。)
size_tってヤツは、
(size_t)sizeof(NSInteger)
こんな感じで取得できるメモリサイズのことですね。
NSInteger, int, long, size_tのメモリサイズを
sizeof( )で見てみましょう。
NSIntegerの定義が32bit端末の場合int型, 64bit端末の場合long型なので、
32bitの場合
NSIntegerのメモリサイズ = intのメモリサイズ = 4
64bitの場合
NSIntegerのメモリサイズ = longのメモリサイズ = 8
でした。
加えて、32bitの場合, 64bitの場合ともに
NSIntegerのメモリサイズ = size_tのメモリサイズ
ということを確認できました。
だから、以下のように書式%zdを使用すれば32bit, 64bit両方に対応できるといった感じですね。
NSInteger hoge = 100;
NSLog(@"output hoge = %zd", hoge);
さいごに
確認したことをいろいろ書いたら長くなってしまいましたが一応整理できました。
文字列操作プログラミングガイド
こちらをもっと早くに読んでおけばよかったなーと思いました。