64bit ARMのプリミティブタイプの長さについて
えーと、新しいアプリを作ってる途中で64bit対応(iPhone 5sだけ?5cも?)しようとしたら、想定(というほど大したものでもなく単なる思い込み)と違う部分が結構あったのでメモっときます。
先に書いときますと、細かいことはだいたいhttp://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdfの受け売りです。LLVMも同じ仕様なのかよく分かりませんがビルドしてる限りでは同じだと思いますのでこれ以上調べてません。
で、上の資料によるとFundamental Data Typesは以下のとおり。他の型の長さも書いてましたが適宜割愛。
Machine Type | Byte size | Alignment |
---|---|---|
Signed half-word | 2 | 2 |
Unsigned word | 4 | 4 |
Signed word | 4 | 4 |
Unsigned double-word | 8 | 8 |
Signed double-word | 8 | 8 |
Unsigned quad-word | 16 | 16 |
Signed quad-word | 16 | 16 |
Half precision | 2 | 2 |
Single precision | 4 | 4 |
Double precision | 8 | 8 |
Quad precision | 16 | 16 |
Data pointer | 8 | 8 |
Cata pointer | 8 | 8 |
次にC/C++の型長と上のMachine Typeとの対応は以下のとおり。64bitならintも64bitだと思ってたんですが違った模様。
C/C++ Type | Machine Type |
---|---|
char | unsigned byte |
unsigned char | unsigned byte |
signed char | signed byte |
[signed] short | signed halfword |
unsigned short | unsigned halfword |
[signed] int | signed word |
unsigned int | unsigned word |
[signed] long | signed word or signed double-word |
unsigned long | unsigned word or unsigned double-word |
[signed] long long | signed double-word |
unsigned long long | unsigned double-word |
float | single precision (IEEE 754) |
double | double precision (IEEE 754) |
long double | quad precision (IEEE 754- 2008) |
でここからが本題なのですがObjective-CのNSIntegerとかは以下のように定義されてます。
// NSObjCRuntime.h #if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64 typedef long NSInteger; typedef unsigned long NSUInteger; #else typedef int NSInteger; typedef unsigned int NSUInteger; #endif #define NSIntegerMax LONG_MAX #define NSIntegerMin LONG_MIN #define NSUIntegerMax ULONG_MAX
同じくCGFloatは以下のように定義。
// CGBase.h #if defined(__LP64__) && __LP64__ # define CGFLOAT_TYPE double # define CGFLOAT_IS_DOUBLE 1 # define CGFLOAT_MIN DBL_MIN # define CGFLOAT_MAX DBL_MAX #else # define CGFLOAT_TYPE float # define CGFLOAT_IS_DOUBLE 0 # define CGFLOAT_MIN FLT_MIN # define CGFLOAT_MAX FLT_MAX #endif typedef CGFLOAT_TYPE CGFloat;
要はNSIntegerもCGFloatもアーキテクチャによって長さが変わるみたいらしいです。
個人的に問題になったのはCoreDataのモデル上でNSIntegerに対応する項目をintにするとどうなるかよく分からんって部分でして、64bitの実機が無いのでとりあえず全部モデル上はInteger 64にしてラッパークラスのプロパティはint64_tに変えるのがが良いのか、Integer 32にしてintのままの方が良いのかよく分からん感じです。
intのままだと64bit上ではNSNotFoundと比較できないので無しかなーという感じで新しいアプリではint64_tに変えてみたのですが、何個かデグってたので一応直したんですけどすぐ審査に提出して良いものやら悩んでおります。
てかどっちみちCoreDataのバックエンドなんかほとんどSQLiteだろうしSQLiteは内部的には型なんか無いのでInteger 32とか64とかやめてくんねーかなー、という思いも若干あったりします。いやCoreDataはSQLiteじゃねーしと言われればそれまでですが。
あとiPhone 5s上では古いXcodeでビルドしたアプリは32bitモードとかで動いたりするんですかね?でないとクラッシュするアプリもあると思うんですが、とか考えてるとなんかもう古いXcodeで良くね?って感じになるんですけどまあ文句ばっかり言っててもしょうがないのでがんばりましょう。
ということでよく分からん方は元資料あたってください。ほんでわ。