- 论坛徽章:
- 0
|
1.前言
相信接触过OC的对NSLog都很熟悉,细心查看NSLog的原始定义,会发现,他的原型如下:
FOUNDATION_EXPORT void NSLog(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>
- @interface RandomArgs : NSObject
- -(int)add:(int)item,...;
- @end
- RandomArgs.m
- #import "RandomArgs.h"
- @implementation RandomArgs
- -(int)add:(int)item,...{
- va_list list;
- va_start(list, item);
- int result=0;
- NSLog(@"第一个参数:%d",item);
- result+=item;
- int arg;
- while ((arg=va_arg(list,int))) {
- NSLog(@"当前参数:%d",arg);
- result+=arg;
- }
- va_end(list);
- return result;
- }
- @end
- main.m
- #import <Foundation/Foundation.h>
- #import "RandomArgs.h"
- int main(int argc, const char * argv[]) {
- @autoreleasepool {
- RandomArgs* rand=[[RandomArgs alloc]init];
- int result=[rand add:4,5,6,nil];
- NSLog(@"结果:%d",result);
- }
- return 0;
- }
复制代码 效果
3.总结
主要是通过循环va_arg来获取,但是要注意的是,第一个参数必须是固定的,循环里面只能获取第二个参数以后的参数。
4.原理
参数在堆栈中分布,位置
在进程中,堆栈地址是从高到低分配的.当执行一个函数的时候,将参数列表入栈,压入堆栈的高地址部分,然后入栈函数的返回地址,接着入栈函数的执行代码,这个入栈过程,堆栈地址不断递减,一些黑客就是在堆栈中修改函数返回地址,执行自己的代码来达到执行自己插入的代码段的目的。
总之,函数在堆栈中的分布情况是:地址从高到低,依次是:函数参数列表,函数返回地址,函数执行代码段。
堆栈中,各个函数的分布情况是倒序的.即最后一个参数在列表中地址最高部分,第一个参数在列表地址的最低部分.参数在堆栈中的分布情况如下:
最后一个参数
倒数第二个参数
...
第一个参数
函数返回地址
函数代码段 |
|