4.原理

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

1.前言相信接触过OC的对NSLog都很熟悉,细心查看NSLog的原始定义,会发现,他的原型如下:

FOUNDATION_EXPORTvoidNSLog(NSString*format,...)NS_FORMAT_FUNCTION(1,2);

路径在:OS X version/Frameworks/Foundation/NSObjCRuntime.h

注意到参数最后的...,这里是可变参数。这样,在调用时就可以根据需要传入相应个数的参数了。

PS:其实在C#中也有params指定可变参数,跟OC这个很类似。

那么,如何在自己写的函数中实现可变参数呢?

2.实现要实现OC中的可变参数,需要几个宏定义va_list、va_start、va_arg、va_end,先实现效果,以无限个整数相加为例:

RandomArgs.h

#import <Foundation/Foundation.h>@interfaceRandomArgs:NSObject-(int)add:(int)item,...;@end

RandomArgs.m

#import "RandomArgs.h"@implementationRandomArgs-(int)add:(int)item,...{va_list list;va_start(list,item);intresult=0;NSLog(@"第一个参数:%d",item);result+=item;intarg;while((arg=va_arg(list,int))){NSLog(@"当前参数:%d",arg);result+=arg;}va_end(list);returnresult;}@end

main.m

#import <Foundation/Foundation.h>#import "RandomArgs.h"intmain(intargc,constchar*argv[]){@autoreleasepool{RandomArgs*rand=[[RandomArgsalloc]init];intresult=[rand add:4,5,6,nil];NSLog(@"结果:%d",result);}return0;}

效果

3.总结主要是通过循环va_arg来获取,但是要注意的是,第一个参数必须是固定的,循环里面只能获取第二个参数以后的参数。

主要参数解释:

参数路径、原型、解释va_list

OS X version/usr/include/sys/_types/_va_list.h/typedef,__darwin_va_list va_list;,这个变量是指向参数地址的指针,因为得到参数的地址之后,再结合参数的类型,才能得到参数的值。

va_start

stdarg.h,#define va_start(ap, param) __builtin_va_start(ap, param),第一个可选参数地址

va_arg

stdarg.h,#define va_arg(ap, type) __builtin_va_arg(ap, type),下一个参数地址

va_end

stdarg.h,#define va_end(ap) __builtin_va_end(ap),将指针置为无效

4.原理参数在堆栈中分布,位置

在进程中,堆栈地址是从高到低分配的.当执行一个函数的时候,将参数列表入栈,压入堆栈的高地址部分,然后入栈函数的返回地址,接着入栈函数的执行代码,这个入栈过程,堆栈地址不断递减,一些黑客就是在堆栈中修改函数返回地址,执行自己的代码来达到执行自己插入的代码段的目的。

总之,函数在堆栈中的分布情况是:地址从高到低,依次是:函数参数列表,函数返回地址,函数执行代码段。

堆栈中,各个函数的分布情况是倒序的.即最后一个参数在列表中地址最高部分,第一个参数在列表地址的最低部分.参数在堆栈中的分布情况如下:

最后一个参数

倒数第二个参数

...

第一个参数

函数返回地址

函数代码段

转载请注明:特维博客 » Objective-C可变参数的函数实现

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航