头文件<stdarg.h>提供了遍历未知数目和类型的喊出参数表的功能。
假定函数f带有可变数目的实际参数,lastar=g是他的最后一个命名的形式参数,那么,在函数f内声明一个类型为va_list的变量ap,它将以此指向每个实际参数:
va_list ap;
在访问任何未命名的参数前,必须用va_start宏宏初始化ap一次:
va_start(va_list ap, lastarg);
此后,每次执行宏va_arg都将产生一个与下一个未命名的参数具有相同类型和数值的值,它同时还修改ap,以使得下一次执行va_arg时返回下一个参数:
type va_arg(va_list ap,type);
在所有参数处理完毕后,且在退出函数f之前,必须调用宏va_end以此,如下所示
void va_end(va_list ap);
其实va_list类型用于声明一个变量,该变量将以此引用各参数,
va_start用于将ap初始化为指向第一个无名参数的指针,在使用ap之前,该宏必须被调用一次。
参数表必须至少包含一个有名参数,va_start将最后一个有名参数作为起点
每次调用va_arg,该函数都将返回一个参数,并将ap指向下一个参数。va_arg使用一个类型名来决定返回的对象类型,指针移动的步长,最后,必须在函数返回之前调用va_end,以完成一些必要的清理工作。
现在我们实现一个简化的printf。
void minprintf(char *fmt,...)
{
va_list ap;//points to each unnamed arg in turn
char *p,*sval;
int ival;
double dval;
va_start(ap,fmt);
for(p=fmt;*p;p++){
if(*p!='%'){
putchar(*p);
continue;
}
switch (*++p){
case 'd':
ival=va_arg(ap,int);
printf("%d",ival);
break;
case 'f':
dval=va_arg(ap,int);
printf("%f",dval);
case 's':
for(sval=va_arg(ap,char*);*sval;sval++)
putchar(*sval);
break;
default:
putchar(*p);
break;
}
}
var_end(ap);
}
下面看下在OC中的应用
先写个show方法
void show(id formatstring,...)
{
va_list arglist;
if (!formatstring) {
return;
}
va_start(arglist, formatstring);
id outString=[[NSStringalloc]initWithFormat:formatstringarguments:arglist];
va_end(arglist);
UIAlertView *alert=[[UIAlertViewalloc]initWithTitle:@"test"message:outString delegate:nilcancelButtonTitle:@"OK"otherButtonTitles:@"Cancel",nil];
[alertshow];
}
在viewdidLoad中
show(@"Test on va_list,va_start,va_end");
接着深入
textView=[[UITextViewalloc]initWithFrame:self.view.frame];
textView.text=@"";
textView.editable=NO;
[self.viewaddSubview:textView];
self.navigationItem.rightBarButtonItem=[[UIBarButtonItemalloc]initWithTitle:@"Test"style:UIBarButtonItemStylePlaintarget:selfaction:@selector(runTests)];
-(void)runTests
{
[[[NSOperationQueuealloc]init]addOperationWithBlock:^{
[selflog:@"\n\nReachability Tests"];
[selflog:@"hostName:%@",[selfhostname]];
[selflog:@"wifiIP:%@",[selfgetWifiIPAddress]];
}];
//或者
// dispatch_async(dispatch_get_global_queue(0, 0), ^{
//
// [self log:@"\n\nReachability Tests"];
// [self log:@"hostName:%@",[self hostname]];
// [self log:@"wifiIP:%@",[self getWifiIPAddress]];
// });
}
-(void)log:(id)formatstring,...
{
va_list arglist;
if (!formatstring) {
return;
}
va_start(arglist, formatstring);
NSString *outString=[[NSStringalloc]initWithFormat:formatstringarguments:arglist];
NSLog(@"--%@--",outString);
va_end(arglist);
dispatch_async(dispatch_get_main_queue(), ^{
NSString *newString=[NSStringstringWithFormat:@"%@\n%@:%@",textView.text,[NSDatedate],outString];
textView.text=newString;
// [textView scrollRangeToVisible:NSMakeRange(newString.length, 1)];
});
//或者
// [[NSOperationQueue mainQueue]addOperationWithBlock:^{
//
// NSString *newString=[NSString stringWithFormat:@"%@\n%@:%@",textView.text,[NSDate date],outString];
// textView.text=newString;
//
// }];
}
-(NSString *)hostname
{
char baseHostName[256];
int success=gethostname(baseHostName,255);
if (success!=0) {
return nil;
}
baseHostName[255]='\0';
#if TARGET_IPHONE_SIMULATOR
return [NSStringstringWithFormat:@"%s",baseHostName];
#else
return [NSString stringWithFormat:@"%s.local",baseHostName];
#endif
}
-(NSString*)getWifiIPAddress
{
BOOL success;
struct ifaddrs*addr=NULL;
const structifaddrs *cursor=NULL;
success=getifaddrs(&addr)==0;
if (success) {
//Loop through linked list of interfaces
cursor=addr;
while (cursor!=NULL) {
if (cursor->ifa_addr->sa_family==AF_INET&&(cursor->ifa_flags&IFF_LOOPBACK)==0) {
NSString *name=[NSStringstringWithUTF8String:cursor->ifa_name];
if ([name hasPrefix:@"en0"]||[namehasPrefix:@"bridge0"])
return [NSStringstringWithUTF8String:inet_ntoa(((structsockaddr_in *)cursor->ifa_addr)->sin_addr)];
}
cursor=cursor->ifa_next;
}
freeifaddrs(addr);
}
return nil;
}
iPhone开发秘籍