- 論壇徽章:
- 0
|
1.前言
相信接觸過OC的對(duì)NSLog都很熟悉,細(xì)心查看NSLog的原始定義,會(huì)發(fā)現(xiàn),他的原型如下:
FOUNDATION_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
路徑在:OS X version/Frameworks/Foundation/NSObjCRuntime.h
注意到參數(shù)最后的...,這里是可變參數(shù)。這樣,在調(diào)用時(shí)就可以根據(jù)需要傳入相應(yīng)個(gè)數(shù)的參數(shù)了。
PS:其實(shí)在C#中也有params指定可變參數(shù),跟OC這個(gè)很類似。
那么,如何在自己寫的函數(shù)中實(shí)現(xiàn)可變參數(shù)呢?
2.實(shí)現(xiàn)
要實(shí)現(xiàn)OC中的可變參數(shù),需要幾個(gè)宏定義va_list、va_start、va_arg、va_end,先實(shí)現(xiàn)效果,以無限個(gè)整數(shù)相加為例:
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(@"第一個(gè)參數(shù):%d",item);
- result+=item;
- int arg;
- while ((arg=va_arg(list,int))) {
- NSLog(@"當(dāng)前參數(shù):%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(@"結(jié)果:%d",result);
- }
- return 0;
- }
復(fù)制代碼 效果
1.png (20.63 KB, 下載次數(shù): 63)
下載附件
2015-06-16 09:14 上傳
3.總結(jié)
主要是通過循環(huán)va_arg來獲取,但是要注意的是,第一個(gè)參數(shù)必須是固定的,循環(huán)里面只能獲取第二個(gè)參數(shù)以后的參數(shù)。
1.png (12.4 KB, 下載次數(shù): 66)
下載附件
2015-06-16 09:15 上傳
4.原理
參數(shù)在堆棧中分布,位置
在進(jìn)程中,堆棧地址是從高到低分配的.當(dāng)執(zhí)行一個(gè)函數(shù)的時(shí)候,將參數(shù)列表入棧,壓入堆棧的高地址部分,然后入棧函數(shù)的返回地址,接著入棧函數(shù)的執(zhí)行代碼,這個(gè)入棧過程,堆棧地址不斷遞減,一些黑客就是在堆棧中修改函數(shù)返回地址,執(zhí)行自己的代碼來達(dá)到執(zhí)行自己插入的代碼段的目的。
總之,函數(shù)在堆棧中的分布情況是:地址從高到低,依次是:函數(shù)參數(shù)列表,函數(shù)返回地址,函數(shù)執(zhí)行代碼段。
堆棧中,各個(gè)函數(shù)的分布情況是倒序的.即最后一個(gè)參數(shù)在列表中地址最高部分,第一個(gè)參數(shù)在列表地址的最低部分.參數(shù)在堆棧中的分布情況如下:
最后一個(gè)參數(shù)
倒數(shù)第二個(gè)參數(shù)
...
第一個(gè)參數(shù)
函數(shù)返回地址
函數(shù)代碼段 |
|