LoginSignup
3
3

More than 5 years have passed since last update.

NSInteger→longのキャストについて考える

Last updated at Posted at 2016-08-20

はじめに

私は、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)
→怒られない。
スクリーンショット 2016-08-20 12.00.43.png

caseB. iPhone5s以降の端末
→怒られる。
スクリーンショット 2016-08-20 11.27.30.png

指定子%dを使用した場合は、
32bit端末では怒られないが、64bit端末では怒られる
ということですね。

2.NSIntegerの値を指定子%ldでログ出力

NSInteger hoge = 100;
NSLog(@"output hoge = %ld", hoge);

caseA. iPhone5以前の端末(and iPhone5c)
→怒られる。
スクリーンショット 2016-08-21 2.43.47.png

caseB. iPhone5s以降の端末
→怒られない。
スクリーンショット 2016-08-21 2.45.04.png

指定子%ldを使用した場合は、
32bit端末では怒られるが、64bit端末では怒られない
ということですね。

1.の%dを使用した場合と2.の%ldを使用した場合ともに
「引数にNSIntegerを使用すべきでない。明示的にlongにキャストすべきだよ。」
というような警告が出ています。
警告の通りlongにキャストしてあげれば、32bit端末でも64bit端末でも怒られません。
スクリーンショット 2016-08-20 12.13.15.png

警告の意味を探る

警告の意味を探るためにNSIntegerがどんなヤツなのか覗いてみました。
スクリーンショット 2016-08-20 11.30.09.png

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( )で見てみましょう。

caseA. 32bit端末
スクリーンショット 2016-08-21 1.49.21.png

caseB. 64bit端末
スクリーンショット 2016-08-21 1.50.47.png

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);

さいごに

確認したことをいろいろ書いたら長くなってしまいましたが一応整理できました。

文字列操作プログラミングガイド
こちらをもっと早くに読んでおけばよかったなーと思いました。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3