温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

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

发布时间:2020-07-21 01:23:06 来源:网络 阅读:591 作者:iKingLai 栏目:移动开发

Struct结构体


c没有面向对象编程的概念。所以为了创建一个复杂的数据结构(不是基本数据类型和数组),你必须使用结构体。在某些Objective-C代码中,你可能甚至经常看到结构体被使用,这样做是为了节省内存。


例如,CGPoint,CGRect,和CGSize都是结构体。苹果开发者把他们作为结构体是因为在iPhone中构建views的时候要频繁的使用到。你可以在Objective-C中使用结构体。


struct point {  

   int x;

   int y;

};


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

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

}


如果你要传递一个大的结构体数据给函数,你应该考虑传递结构体指针,这样能够避免拷贝整个结构体(因为是值传递)。在其他通常情况下你会看到结构体指针。


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

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

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





向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI