美文网首页
Objective-C中可选参数的实现

Objective-C中可选参数的实现

作者: bada | 来源:发表于2015-11-30 12:02 被阅读0次

代码:

-(NSString*)makeDrink:(NSString*)drink Fruit:(NSString*)fruit Food:(NSString*)foodOne,...;

{

NSMutableArray* arr = [[NSMutableArrayalloc]init];

va_listparams;

idargument;

if(foodOne) {

va_start(params, foodOne);

while((argument =va_arg(params,id))) {

[arraddObject:argument];

}

va_end(params);

}

returnnil;

}

------------------------------------------------------------

用法:

Person *man = [Person alloc] init];

[man makeDrink:@"beer" Fruit:@"banana" Food:@"rice",@"beef",@"fish",@"potato",@"vegetables",nil];

------------------------------------------------------------

知识点:

va_list/va_start/va_arg/va_end这几个宏,都是用于函数的可变参数的。

我们来看看在vs2008中,它们是怎么定义的:

1:///stdarg.h

2:#defineva_start _crt_va_start

3:#defineva_arg _crt_va_arg

4:#defineva_end _crt_va_end

5:

6:///vadefs.h

7:#define_ADDRESSOF(v)  ( &reinterpret_cast(v) )

8:  typedefchar*  va_list;

9:#define_INTSIZEOF(n)  ( (sizeof(n) +sizeof(int) - 1) & ~(sizeof(int) - 1) )

10:#define_crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )

11:#define_crt_va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

12:#define_crt_va_end(ap)      ( ap = (va_list)0 )

代码原图

再看看各个宏的功能是什么?

va_list用于声明一个变量,我们知道函数的可变参数列表其实就是一个字符串,所以va_list才被声明为字符型指针,这个类型用于声明一个指向参数列表的字符型指针变量,例如:va_list ap;//ap:arguement pointer

va_start(ap,v),它的第一个参数是指向可变参数字符串的变量,第二个参数是可变参数函数的第一个参数,通常用于指定可变参数列表中参数的个数。

va_arg(ap,t),它的第一个参数指向可变参数字符串的变量,第二个参数是可变参数的类型。

va_end(ap) 用于将存放可变参数字符串的变量清空(赋值为NULL).

va_start的功能是要把,ap指针指向可变参数的第一个参数位置处,

#define_crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )

先取第一个参数的地址,在sum函数中就是取number的地址并且将其转化为char *的(因为char *的指针进行加减运算后,偏移的字节数才与加的数字相同, 如果为int *p,那么p+1实际上将p移动了4个字节),然后加上4(__INITSIZEOF(number)=(4+3)&~3),这样就将ap指向了可变参数字符串的第一个参数。

#define_INTSIZEOF(n) ( (sizeof(n) +sizeof(int) - 1) & ~(sizeof(int) - 1) )

以int所占的字节为标准进行对其操作。

如果int占四字节,则以四字节对齐为标准读取数据。

va_arg是要从ap中取下一个参数。

#define_crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

对于这个宏,哥纠结了很久,最后终于搞清楚了,究其原因就是自己C语言功底不扎实,具体表现在没有搞清楚赋值表达式的值是怎么运作的。

我们看这个宏,首先是ap = ap + __INTSIZEOF(t)。注意到,此时ap已经被改变了,它已经指向了下一个参数,我们令x=ap + __INTSIZEOF(t);

那么括号内就变成了(x – __INTSIZEOF(t)),但是这里没有赋值运算符,所以ap的值没有发生变化,此时ap仍然指向的是当前参数的下一个参数的位置,

也就是说ap指向的位置比当前正在处理的位置超前了一个位置。

其实写成下面的形式就简单明了了:

#define   va_arg(ap,t)   (*(t   *)((ap   +=   _INTSIZEOF(t)),ap   -   _INTSIZEOF(t)))

分析:为什么要将ap指向当前处理参数的下一个参数了?

经过上面的分析,我们知道va_start(ap,v)已经将ap指向了可变参数列表的第一个参数了,以后我们每一步操作都需要将ap移动到下一个

参数的位置,由于我们每次使用可变参数的顺序是:va_start(ap,v)—>va_arg(ap,t);这样我们在第一次去参数的时候,其实ap已经指向了

第二个参数开始的位置,所以我们用表达式的方式获得一个指向第一个参数的临时指针,这样我们就可以采用这种一致的方式来处理可变参数列表。

(感觉没表达的十分清楚,希望各位朋友纠正~~~~~~)。

下图是我的例子程序中去参数的情况(时间仓促,画得很丑,请原谅):

va_end(ap)  将声明的ap指针置为空,因为指针使用后最后设置为空。

参考资料:

http://topic.csdn.net/u/20110830/15/a3630fc4-3c5f-4a1e-bbee-949ba7b4cbe0.html

http://topic.csdn.net/u/20070120/12/e8b7363b-6404-4d91-9307-01e5ed996f3d.html

相关文章

  • Objective-C中可选参数的实现

    代码: -(NSString*)makeDrink:(NSString*)drink Fruit:(NSStrin...

  • swift5 基本语法-可选类型&强制解包

    可选类型(Optionals) Objective-C中没有可选类型的概念,但是swift中的可选(Optiona...

  • Swift 可变参数& Objective-C 可变参数

    Objective-C中可变参数的API很多,如: 像以上方法中的最后一个参数, ...如何实现实现呢?如下: 调...

  • swift3 笔记 可选协议 和 协议扩展

    Objective-C 可选协议 -> 非必须实现 使用 @optional 关键字 Swift 可选协议 第一种...

  • Dart独特的使用方式(session one)

    1.位置可选参数 Dart中的函数可以包含可选参数。可选参数是函数调用者可以选择不提供的参数。可以在函数内检查可选...

  • Dart中的函数

    定义函数 函数参数 可选参数{}中的参数是可选参数 位置参数[]中定义的参数是位置参数, 位置必须一一对应 默认参...

  • 利用reduce和filter,对对象数组操作

    数组 结果 代码实现 参数 reduce参数描述回调函数func初始值(可选)initValue func参数描述...

  • 磨刀- Dart 函数

    ✨✨✨✨✨ 魏什么_多喝水 Flutter 之路 声明 参数 可选参数 可选命名参数: 可选位置参数

  • Flutter-选填参数

    可选命名参数用 {}表示可选命名的参数必须要写参数名,可以跳过一些参数 调用方法: 可选位置参数用[]表示可选位置...

  • dart

    "_" 不同文件中才有私有效果,如果是同一.dart文件中,则没有私有效果。 可选参数 用[]包围的参数是可选参数...

网友评论

      本文标题:Objective-C中可选参数的实现

      本文链接:https://www.haomeiwen.com/subject/afrjhttx.html