首页投稿(暂停使用,暂停投稿)iOS Developer

来自MixPanel的Log写法

2016-08-10  本文已影响99人  iLees

<h6>首先看一下代码:</h6>

static inline void MPLog(NSString *format, ...) {
    __block va_list arg_list;
    va_start (arg_list, format);
    NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:arg_list];
    va_end(arg_list);
    NSLog(@"[Mixpanel] %@", formattedString);
}

#ifdef MIXPANEL_DEBUG
#define MixpanelDebug(...) MPLog(__VA_ARGS__)
#else
#define MixpanelDebug(...)
#endif

<h6>重点关注的是MPLog的实现,我们可以分以下两点解剖该函数:</h6>
1、static inline
inline函数有点类似于宏,内联函数代码会被直接嵌入到被调用的地方,调用几次就会嵌入几次。这样省去了函数调用时的一些额外开销,例如保存和恢复函数返回地址等等。这样加快了速度,但调用次数多的话,会导致可执行文件变大。为了避免这一弱点,内联函数一般都会和static一起出现,从而避免被其它编译单元调用。

2、va_start、va_start
在C语言中,我们经常会见到这样的传参方式:

void func(part_list, ...);

函数参数是以栈的形式存取的,从右至左入栈。参数存放在内存的堆栈段中,在执行函数的时候,从最后一个开始入栈,这样栈底是高地址栈顶是低地址。例如:void func(int x, float y, char z);函数调用的时候,进栈顺序是z->y->x,内存中变量存放次序是x->y->z。因此,我们只要知道一个变量的地址和其他变量的类型,通过指针移位运算就可以顺藤摸瓜找到其它的参数,例如:


void fun(int a, ...) 
{ 
  int *temp = &a;
  temp++;
  for (int i = 0; i < a; ++i) 
  { 
    cout << *temp << endl; 
    temp++; 
  } 
}
int main() 
{ 
  int a = 1; 
  int b = 2; 
  int c = 3; 
  int d = 4; 
  fun(4, a, b, c, d); 
  system("pause"); 
  return 0; 
} 

Output:: 
1 
2 
3 
4

对于获取省略号指定的参数,在函数体中声明一个va_list,然后用va_start函数来获取参数列表中的参数,使用完毕后调用va_end来结束,例如:

/*函数原型声明,至少需要一个确定的参数,注意括号内的省略号*/ 
int demo( char, ... ); 
void main( void ) 
{ 
   demo("DEMO", "This", "is", "a", "demo!", ""); 
} 

/*括号内的省略号表示可选参数*/ 
int demo( char msg, ... ) 
{ 
       /*定义保存函数参数的结构*/
   va_list argp; 
   int argno = 0; 
   char para; 
     /*argp指向传入的第一个可选参数,msg是最后一个确定的参数*/ 
   va_start( argp, msg ); 
   while (1) 
       { 
        para = va_arg( argp, char); 
           if ( strcmp( para, "") == 0 ) 
               break; 
           printf("Parameter #%d is: %s\n", argno, para); 
           argno++; 
} 
va_end( argp ); 
/*将argp置为NULL*/
return 0; 
}
上一篇 下一篇

猜你喜欢

热点阅读