使用本地c/c++提高iOS性能 之三

Struct結構體
node


c沒有面向對象編程的概念。因此爲了建立一個複雜的數據結構(不是基本數據類型和數組),你必須使用結構體。在某些Objective-C代碼中,你可能甚至常常看到結構體被使用,這樣作是爲了節省內存。算法


例如,CGPoint,CGRect,和CGSize都是結構體。蘋果開發者把他們做爲結構體是由於在iPhone中構建views的時候要頻繁的使用到。你能夠在Objective-C中使用結構體。編程


struct point {  數組

   int x;
數據結構

   int y;app

};ide


struct point add_point(struct point p1, struct point p2) {函數

   p1.x += p2.x;
   p1.y += p2.y;
   return p1;
oop

} 性能


若是你要傳遞一個大的結構體數據給函數,你應該考慮傳遞結構體指針,這樣可以避免拷貝整個結構體(由於是值傳遞)。在其餘一般狀況下你會看到結構體指針。


struct point origin;
struct point *porigin;
porigin = &origin;
printf("origin is (%d, %d) \n" , (*porigin).x , (*porigin ).y );


動態內存分配


和Objective-C比較,c中的內存管理有一些相同點和不一樣點。在c中,你能夠create和allocate內存給對象;若是你爲一個對象分配了內存,你不要手動的deallocate/free這個對象,釋放內存。在Objective-C的autorelease或Autorelease Pool中,沒有這樣的概念。


爲了對c中的內存管理有一個很好的理解,你必須記住4個重要的函數,如表格9-1

  • malloc:你能夠申請一個指定大小的內存快,而後返回一個void類型的指針。你能夠把這個指針轉換成你指定的類型,如:


       my_ptr = (cast_type *)malloc(number_of_bytes); // General format
       my_ptr = (int *)malloc (100 * sizeof(int)); // allocate a pointer of integer with size

       //of 100 integer


  • calloc:它一般用來申請多個內存塊,每一個塊的大小相同,而後把他們全部字節都設置爲0

       my_ptr = (cast_type *)calloc(number_of_elements, size_of_element); // General format

       my_ptr = (int *)calloc (100, sizeof(int)); // allocate a pointer of integer with size

       // of 100 integer


  • free:這個內存管理機制相似於Objective-C:你分配的內存,你須要釋放它。你能夠在c中使用free進行釋放。


       free(my_ptr);


  • realloc:有時候你爲對象或數組分配的內存不夠,所以你須要改變內存的大小,經過realloc能夠用實現。


       realloc(my_ptr, 200 * sizeof(int));


注意:你不能再一次使用函數 malloc/calloc,由於將會擦除你指針指向的內存中存儲的數據。



Linked List 例子


是時候從理論中走出來,而後開始寫代碼了。你將用你學到的知識來解決用鏈表存儲數據的問題。已經在第5章學習了用Ogjective--C來實現。如今,你將學會如何用c寫一個鏈表,在不少狀況下,會有更高的性能。


#include <stdio.h>

#include <stdlib.h>

struct Node {
   int  number;
   struct Node *next;

};


爲了獲得一個鏈表,你須要一個結構體引用自身。節點結構體內部須要有一個link來指向下一個結構體節點。在c中,你能夠在頭文件或實現文件中聲明方法接口。


void append_node(struct Node *list, int num);

void display_list(struct Node *list);


int main(void) {

   struct Node *list;

   list = (struct Node *)malloc(sizeof(struct Node));list->number = 0;
   list->next = NULL;

   append_node(list, 1);

   append_node(list, 5);append_node(list, 3);

   display_list(list);

   // delete a list here. free(list) will not work

   return(0);

}


void delete_list(struct Node *list) {

   // do it as your exercise

}


void display_list(struct Node *list) {
   // loop over the list to print the value out.while(list->next != NULL) {

   printf("%d ", list->number);

   list = list->next;}

   printf("%d", list->number);

}


void append_node(struct Node *list, int num) {

// go into the end of the list

while(list->next != NULL)

   list = list->next;

   // set the next property for the last Node object.

   list->next = (struct Node *)malloc(sizeof(struct Node));

   list->next->number = num;
   list->next->next = NULL;

}


你能夠看到,由於你的鏈表沒有固定大小,你老是要使用malloc來分配新的元素。在用完鏈表以後,你要刪除它。你須要記住內存管理規則:對於每次調用malloc或calloc,你須要調用free函數;不然,會有內存泄露。像在代碼中的警告註釋,簡單的調用free(list)會致使一些內存泄露。我將delete_list的實現做爲一個練習留給你來作。


函數指針


在c中,函數不是一個變量,可是你能夠定義一個指針指向它,就像定義指針指向一個整數或結構體。你能夠把這些指針放到一個數組中,而後把這些函數指針做爲參數傳遞給其餘函數。這個和Objective-C中的selector是相似的。


接下來你會看到一個簡單的例子,在快速排序算法中實現了一個比較方法。qsort是c中的一個內置函數,可以獲得一個函數指針,而後使用快速排序算法對數組進行排序。


這是qsort的接口:


void qsort (void *array, int number_of_elements, int size_of_element, int (* comparator)

(const void *, const void *) );


你須要一個比較函數,它接收兩個指針,返回一個整數表示什麼值更大。


int compare (const void * a, const void * b) {

       return ( *(int*)a - *(int*)b );

}


而後你能夠把它做爲參數傳遞給qsort函數。


int main () {

   int values[] = { 40, 10, 100, 90, 20, 25 };
   qsort (values, 6, sizeof(int), compare); // pass in the compare function here.return 0;

}



Bitwise Operators位操做符


位操做運算比加法和減法稍快一些,比乘法和除法快不少。你也許會在一些庫中看到使用位操做符,尤爲是用比較老的微處理器寫的。


瞭解位操做符可以幫助你操做位,在密集型計算中獲得更好的性能。只有幾個位操做符合移位操做符須要記住:NOT, AND, OR, XOR, left shfit,和right shift。

  • NOT   邏輯非,0變1,1變0.

    NOT     0111 = 1 000

  • AND 邏輯與,只要有一個爲0,結果就是0;不然爲1

    0 1 0 1

    0 0 1 1

AND

      0 0 0 1

  • OR  邏輯或,只要有一個爲1,結果就是1;不然爲 0


       0 0 1 0

       1 0 0 0

OR

       1 0 1 0

  • XOR 邏輯異或,相同爲0,不一樣爲1


       0 1 0 1

       0 0 1 1

XOR

       0 1 1 0


使用這些位操做符,你可以很是快的改變bit值。若是你不常用位操做的話,這看起來會很是的奇怪。我會在Objective-c中給你一個說明。這裏有一個使用了位操做的Cocoa Touch Framework中的應用,假設你已經對NSCalendar很是熟悉了。


在一個NSCalendar中,你能夠基於一個輸入參數獲得一個指定日期的日期組件列表。例如,若是你想要一個NSDataComponent對象,它包含了你想要的日期組件,你可使用下面的源代碼:


NSUInteger unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;

NSDateComponents *dateComponents = [calendar components:unitFlags

fromDate:startDatetoDate:endDate

options:0];


當方法[calendar components:fromDate:toDate:options] 使用unitFlag被調用時,會檢查調用者須要什麼樣的日期組件,而後會返回一個確切的組件類型。這樣讀寫代碼都是很是方便的,只須要使用OR操做符。


在方法[calendar components:fromDate:toDate:options] 中,會使用 AND 操做符檢查unitFlag的值。


BOOL hasYear = (unitFlags & NSYearCalendarUnit) != 0;

BOOL hasMonth = (unitFlags & NSMonthCalendarUnit) != 0;

BOOL hasWeek = (unitFlags & NSWeeCalendarUnit) != 0;
...


如今,我詳細解釋一下內部發生了什麼以及是如何工做的。首先,每一個flagNSYearCalendarUnit, NSMonthCalendarUnit,等等 )被賦予了一個惟一的二進制值,用這樣的格式來表示:0100,1000。


當你在這三個flags上進行OR操做時,你會獲得相似1011這樣的值。你把這個值傳遞給方法

[calendar components:fromDate:toDate:options] 。在這個方法的內部,它會將存儲在內部的每個flag作AND操做。


1011 & 0100 = 0100there is a NSYearCalendarUnit.

1011 & 1000 = 1000 there is a NSMonthCalendarUnit


相比其餘普通的方法(要麼傳遞不少參數,要麼使用一個很大的枚舉,或者須要一個很大的循環來檢查數據),使用這種方法將會提高你應用程序的性能。


  • 位的移動:當你要乘或除一個2的倍數時,你能夠對位進行左移或右移。例如,若是你要乘或除2,4,6,8,16......,你能夠考慮使用位的移動,比直接使用乘法或除法性能高不少。你只能在整數上

    進行位的移動。



有兩個移位操做符:左移和右移。整數是以二進制的形式存儲的,例如0000 0110(十進制是6)。


  • 左移:把左邊的位移出去,右邊用0補充。若是你左移了n位,至關於乘了2的n次方。    

    0000 0110 << 1  = 0000 1100 (十進制12)
  • 右移:把右邊的位移出去,左邊用c補充。若是你右移了n位,至關於除了2的n次方。

    0000 0110 >> 1  = 0000 0011(十進制3)      

相關文章
相關標籤/搜索