天天看點

xcode armv7 armv7s arm64

armv6 armv7 armv7s arm64引起編譯包翻倍增大的問題,下邊來說一下關于ios這個指令集

目前ios的指令集有以下幾種:

  • armv6
    • iPhone
    • iPhone2
    • iPhone3G
    • 第一代和第二代iPod Touch
  • armv7
    • iPhone4
    • iPhone4S
  • armv7s
    • iPhone5
    • iPhone5C
  • arm64
    • iPhone5S

 機器對指令集的支援是向下相容的,是以armv7的指令集是可以運作在iphone5S的,隻是效率沒那麼高而已~

在xcodeTARGETS裡邊Architectures:

xcode armv7 armv7s arm64

Architecture : 指你想支援的指令集。

Valid architectures : 指即将編譯的指令集。

Build Active Architecture Only : 隻是否隻編譯目前适用的指令集。

================================================

 現在是2014年初,其實4和4S的使用者還是蠻多的,而iphone3之類的機器幾乎沒有了,是以我們的指令集最低必須基于armv7.

是以,Architecture的值選擇:armv7 armv7s arm64

PS:選arm64時需要最低支援5.1.1:

Convert Your App to a 64-Bit Binary After Updating It for iOS 7

Xcode 5.0.1 can build your app with both 32-bit and 64-bit binaries included. This combined binary requires a minimum deployment target of iOS 5.1.1 or later. The 64-bit binary runs only on 64-bit devices running iOS 7.0.3 and later. If you have an existing app, you should first update your app for iOS 7 and then port it to run on 64-bit processors. By updating it first for iOS 7, you can remove deprecated code paths and use modern practices. If you’re creating a new app, target iOS 7 and compile 32-bit and 64-bit versions of your app.

The architecture for 64-bit apps on iOS is almost identical to the architecture for OS X apps, making it easy to create a common code base that runs in both operating systems. Converting a Cocoa Touch app to 64-bit follows a similar transition process as the one for Cocoa apps on OS X. Pointers and some common C types change from 32 bits to 64 bits. Code that relies on the 

NSInteger

 and 

CGFloat

 types needs to be carefully examined.

Start by building the app for the 64-bit runtime, fixing any warnings that occur as well as searching your code for specific 64-bit issues. For example:

  • Make sure all function calls have a proper prototype.
  • Avoid truncating 64-bit values by accidentally assigning them to a 32-bit data type.
  • Ensure that calculations are performed correctly in the 64-bit version of your app.
  • Create data structures whose layouts are identical in the 32-bit and 64-bit versions of your app (such as when you write a data file to iCloud).

1,如果想自己的app在各個機器都能夠最高效率的運作,則需要将Build Active Architecture Only改為NO,Valid architectures選擇對應的指令集:armv7 armv7s arm64。這個會為各個指令集編譯對應的代碼,是以最後的 ipa體積基本翻了3倍,Release版本必須NO。

2,如果想讓app體積保持最小,則現階段應該選擇Valid architectures為armv7,這樣Build Active Architecture Only選YES或NO就無所謂了

從iPhone 5S的A7 CPU開始到剛剛釋出的iPhone 6(A8 CPU)都已經支援64-bit ARM 架構。關于64-bit的介紹詳見維基百科。知乎上有很多關于蘋果使用A7,A8晶片的讨論,可以參考 iPhone 6 的 Apple A8 晶片對比 Apple A7 提升明顯嗎?, iPhone 5s 配備的 A7 處理器是 64 位,意味着什麼?

  • 1.Xcode 5.0.1開始支援編譯32-bit和64-bit的Binary
  • 2.同時支援32-bit和64-bit,我們需要選擇的minimum deployment target為 iOS 5.1.1
  • 3.64-bit的Binary必須運作在支援64-bit的CPU上,并且最小的OS版本要求是 7.0.3

關于Xcode “Build Setting”中的Architectures參數問題

  • 1.Architectures:你想支援的指令集。(支援指令集是通過編譯生成對應的二進制資料包實作的,如果支援的指令集數目有多個,就會編譯出包含多個指令集代碼的資料包,造成最終編譯的包很大。)
  • 2.Valid architectures:即将編譯的指令集。(Valid architectures 和 Architecture兩個集合的交集為最終編譯生成的版本)
  • 3.Build Active Architecture Only:是否隻編譯目前裝置适用的指令集(如果這個參數設為YES,使用iPhone 6調試,那麼最終生成的一個支援ARM64指令集的Binary。一般在DEBUG模式下設為YES,RELEASE設為NO)

關于指令集如下參考:

ARMv8/ARM64: iPhone 6(Plus), iPhone 5s, iPad Air(2), Retina iPad Mini(2,3)

ARMv7s: iPhone 5, iPhone 5c, iPad 4 

ARMv7: iPhone 3GS, iPhone 4, iPhone 4S, iPod 3G/4G/5G, iPad, iPad 2, iPad 3, iPad Mini   

ARMv6: iPhone, iPhone 3G, iPod 1G/2G 

對于支援64-bit,我們可以設定Architectures為 Standard architectures,在最新的Xcode 6上,它包括 armv7和arm64。

讓App支援32-bit和64-bit基本步驟

1.確定Xcode版本号>=5.0.1

2.更新project settings, minimum deployment target >= 5.1.1

3.改變Architectures為 Standard architectures(include 64-bit)

4.運作測試代碼,解決編譯warnings and errors,對照本文檔或者官方文檔 64-Bit Transition Guide for Cocoa Touch對相應地方做出修改。(編譯器不能告訴我們一切)

5.在真實的64-bit機器上測試。

6.使用Instruments檢視記憶體使用問題。

64-bit主要的變化

64-bit運作時環境和32-bit運作時環境主要有以下兩點的不同:

資料類型的改變

方法調用上的改變

資料類型的改變

整型資料類型的變化如下:

xcode armv7 armv7s arm64

關于位元組對齊的概念可以參考如下連結:C語言位元組對齊

浮點型類型的改變如下:

xcode armv7 armv7s arm64

資料類型的改變可能會為我們的程式帶來這些影響:

1.增加記憶體壓力

2.64-bit到32-bit資料之間的互相轉化

3.計算可能産生不同的結果

4.當把一個值從大的資料類型拷貝到小的資料類型,資料可能被截斷。(NSInteger -> int)

方法調用上的改變

基于32-bit的CPU和基于64-bit上的CPU有不同數量的寄存器,在方法調用上有不同的協定。是以32-bit和64-bit在彙編層級上是不同的。如果我們在程式中不使用彙編程式設計,調用協定很少會遇到。

如何編寫健壯的64-bit代碼

根據上述改變,官方文檔 64-Bit Transition Guide for Cocoa Touch給出如下7步:

1.不要将長整型long指派給整型int (64-bit上會導緻資料丢失)

2.不要将指針類型pointer指派給整型int (64-bit導緻位址資料丢失)

3.留意數值計算(掩碼計算,無符号整數和有符号整數同時使用等)

4.留意對齊方法帶來的變化

5.32-bit到64-bit之間資料轉化(通過網絡傳遞的使用者資料,可能同時存在于32-bit和64-bit的環境下)

6.重寫彙編代碼

7.不要在可變參數方法和不可變參數方法之前進行強制轉化

在LLVM編譯器中,枚舉類型也可以定義枚舉的大小。我們在使用中,指派枚舉值到一個變量時,應該使用适當的資料類型。

不要将指針類型pointer指派給整型int

1 2 3 4 5 6 7 8

int a = 5;

int *c = &a;

int *d = (int *)((int)c + 4); 

int *d = c + 1;

如果我們一定要把指針轉化為整型,可以把上述代碼改為:

1 2

int *d = (int *)((uintptr_t)c + 4);

檢視uintptr_t定義為 typedef unsigned long uintptr_t;

保持資料類型一緻

方法使用時,入參,出參和指派都需要注意保持資料類型一緻。在iOS App中尤其要注意以下幾個類型的正确使用:

  • long
  • NSInteger
  • CFIndex
  • size_t

在32-bit和64-bit下,fpos_t和off_t都是64 bits的資料大小,永遠不要把它們指向int整型。

1 2 3 4 5 6 7 8 9 10 11 12 13

long PerformCalculation(void);

int c = PerformCalculation(); 

// 錯誤 64-bit上資料将被截取

long y = PerformCalculation(); 

// 正确

int PerformAnotherCalculation(int input);

long i = LONG_MAX;

int x = PerformCalculation(i); 

// 錯誤

int ReturnMax()

{

return

LONG_MAX; 

// 錯誤

}

Cocoa中常見的資料類型轉化問題

NSInteger : 在32-bit和64-bit下有分别的定義:

1 2 3 4 5

#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64

typedef long NSInteger;

#else

typedef int NSInteger;

#endif

我們永遠不應該假設NSInteger和int是一樣大的,下面的例子在使用中就需要注意:

1.使用NSNumber對象轉化時

2.使用NSCoder編解碼的時候,如果在64-bit裝置下對NSInteger編碼,在32-bit裝置下對NSInteger解碼。解碼時如果值的大小超過了32-bit,這個時候就會出現異常

3.Famework中使用NSInteger定義的一些常量

CGFloat: 和NSInteger一樣有不同的定義

1 2 3 4 5 6 7

typedef CGFLOAT_TYPE CGFloat;

#if defined(__LP64__) && __LP64__

# define CGFLOAT_TYPE double

#else

# define CGFLOAT_TYPE float

#endif

下面給出錯誤示範:

1 2 3 4 5

CGFloat value = 200.0;

CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &value); 

//64-bit下出現錯誤

CGFloat value = 200.0;

CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &value); 

//正确

整型數值計算問題

關于C語言的符号位擴充可參考資料為:符号位擴充

我們直接來看例子:

1 2 3 4 5 6 7 8 9

int a = -2;

unsigned int b = 1;

long c = a + b;

long long d = c;

printf(

"%lld\n"

, d);

問題:這段代碼在32-bit下運作結果符合我們的預期,輸出為 -1(0xffffffff)。在64-bit下運作結果為:4294967295 (0x00000000ffffffff)。

原因:一個有符号的值和一個同樣精度的無符号的值相加結果是無符号的。這個無符号的結果被轉換到更高精度的數值上時采用零擴充。

解決方案:把變量b換成長整型long

建立資料結構時使用合适的資料大小

C99提供了内置的資料類型保證了一緻的資料大小,即使底層的硬體結構不同。在某些case下,我們知道資料是一個固定的大小或者一個特定的變量擁有一個有限的取值範圍。這個時候,我們應該選擇特定的類型以避免浪費記憶體。

類型如下:

xcode armv7 armv7s arm64

永遠不要使用malloc去為變量申請特定記憶體的大小,改為使用sizeof來擷取變量或者結構體的大小。

另外我們還需要注意修改格式化字元串來同時支援32-bit和64-bit。

xcode armv7 armv7s arm64

小心處理方法和方法指針

1 2 3 4 5 6 7 8

int fixedFunction(int a, int b);

int variadicFunction(int a, ...);

int main

{

int value2 = fixedFunction(5,5);

int value1 = variadicFunction(5,5);

}

上述兩個方法中,在32-bit下使用相同的指令讀取參數的資料,但是在64-bit上,是使用完全不同的協定來編譯的。

如果在代碼中傳遞方法指針,應該保證方法調用的協定是一緻的。永遠不要将一個可變參數的方法轉化成固定參數的方法。

1 2 3 4

int MyFunction(int a, int b, ...);

int (*action)(int, int, int) = (int (*)(int, int, int)) MyFunction;

action(1,2,3); 

// 錯誤示範

上述錯誤的寫法,編譯器是不會提示警告或者錯誤的,并且在模拟器中也不會暴露出問題來。在釋出自己的App前,一定記得要使用真機去測試。

總結

在支援64-bit過程中,應該按照Apple文檔中提供的7個步驟完整檢查項目工程。如果工程中涉及到大量的C或者C++代碼,在支援64-bit中要更加謹慎。