驚愕の事実。Objective-Cのintとlongの最大値は同じだった。

WEBサービスのデータ設計をするときに、ID値を32bitの範囲にするか、64bitの範囲にするかというのは、結構悩みますよね。

32bitというのは、だいたい21億くらいです。ユーザーが21億人を超えることはまずないので、ユーザーIDは32bitで設計しますが、お知らせIDなどは膨大になると想定して64bitまで使えるように設計したりします。

64bitというと、MySQLではカラム定義をbigintにし、Javaではフィールドをlongで定義します。

最近は個人的に、サーバサイドをJavaで記述し、アプリのクライアントサイドをObjective-Cで記述することが多いのですが、このlongの取り扱いで大事故を起こすところでした。

Objective-Cのlongは、64bitではない

これはiOSの話で、Macアプリで使うObjective-Cは違うのですが、Objective-Cのlongは実は32bitしか表現できないという事実を知りました。

32bitということは、intと同じです。

サーバサイドにあわせてlongにすれば64bit表現できると思っていたのですが、実はlongにしても表現できる範囲はintと同じで、32bitの範囲しか保持できません。

雰囲気を出すために画像を貼ってみましたが内容に意味はありません。

INT_MAXとLONG_MAXは同じ

そもそもこれになぜ気づいたかといえば、INT_MAXとLONG_MAXという定数を出力してみたことからでした。

NSLog(@"INT_MAX: %d", INT_MAX);
NSLog(@"LONG_MAX: %ld", LONG_MAX);

これは一見LONG_MAXの方が大きな値を出力しそうですが、実は同じ値が出力されます。

INT_MAX: 2147483647
LONG_MAX: 2147483647

intとlongのメモリサイズも同じ

「嘘でしょ!」と思いsizofでメモリサイズを出力させてみました。

NSLog(@"sizeof(int): %ld", sizeof(int));
NSLog(@"sizeof(long): %ld", sizeof(long));

結果はこちら。

sizeof(int): 4
sizeof(long): 4

どちらも4バイト、つまり32bitで、同じサイズです。

longでもINT_MAXを超えるとオーバーフローする。

まだ信じられないので、longにINT_MAXの値を入れて、さらに1を足してみます。

int i = INT_MAX;
i++;
NSLog(@"int i: %d", i);
 
long l = (long)INT_MAX;
l++;
NSLog(@"long l: %ld", l);

結果がこちら。

int i: -2147483648
long l: -2147483648

longでも、INT_MAXを超えるとオーバーフローします。intとlongが同じサイズだったなんて・・・。

64bitの範囲を表現したければlong longを使う

そういうわけで、iOSのObjective-Cで、64bitの表現をしたければ、long long型を使う必要があります。

NSLog(@"LONG_LONG_MAX: %lld", LONG_LONG_MAX);
NSLog(@"sizeof(long long): %ld", sizeof(long long));

long longの最大値は、9223372036854775807。メモリ上のサイズは8バイト、つまり64bitになります。

LONG_LONG_MAX: 9223372036854775807
sizeof(long long): 8

こちらも、同様にINT_MAXを超えられるか試してみます。

long long ll = (long long)INT_MAX;
ll++;
NSLog(@"long long ll: %lld", ll);
long long ll: 2147483648

こちらはちゃんと、INT_MAXを超えることができました。

そういうわけで、iOSのObjective-Cでintとlongの最大値は同じで、Javaのlongを単純にObjective-Cのlongで受けようと思うとオーバーフローしてしまうので注意が必要です。

・・・なんてことに驚愕していたのは僕だけでしょか?(厳密にはObjective-Cじゃなくて処理系の話ですが)

About katty0324

One comment

Leave a Reply

Scroll To Top