variable number of arguments function

1 minute read

背景

有些时候可能需要函数能够接收任意个参数, 比方说fprintf()函数,

int fprintf(FILE *stream, const char *format, ...);  
  
  
... 表示的是任意个数的参数.  

类似的还有execl和execlp :

 int execl(const char *path, const char *arg, ...);  
 int execlp(const char *file, const char *arg, ...);  

要写一个可以接收任意个参数的函数, 要用到stdarg.h

例1 :

void print_ints(int args, char * name, …) 这个函数里面, 至少要有一个固定的参数, 因为va_start宏需要知道…参数是这个固定参数后面开始的.

在va_start执行后, 每执行一次 va_arg 将依次返回…里面的参数的值。

va_arg的第二个参数代表正在获取的参数的类型, 如本例是int. 当然, 如果你传入的…里面包含了int, char 或者其他的类型的话, 调用va_arg则需要注意了.

args在这里被用于表示…里面有几个参数, 如果args的值小于真正传入的…参数个数, 会造成末端的参数读不到. 如果是大于真正传入的参数个数,

则可能得到不可预知的值.

[root@db-172-16-3-150 zzz]# cat a.c  
#include <stdio.h>  
#include <stdarg.h>  
  
void print_ints(int args, char * name,  ...) {  
  va_list ap;  
  va_start(ap, name);  
  int i;  
  for (i=0; i<args; i++) {  
    fprintf(stdout, "%s : %i\n", name, va_arg(ap, int));  
  }  
  va_end(ap);  
}  
  
int main() {  
  char * name = "digoal";  
  print_ints(3, name, 100, 99, 88);  
  name = "DIGOAL";  
  print_ints(6, name, 100, 99, 88, 77, 66, 55, 44);  
  return 0;  
}  

结果 :

[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g ./a.c -o a && ./a  
digoal : 100  
digoal : 99  
digoal : 88  
DIGOAL : 100  
DIGOAL : 99  
DIGOAL : 88  
DIGOAL : 77  
DIGOAL : 66  
DIGOAL : 55  
// args=6, 实际...里面有7个参数, 所以最后的44未打印.  
DIGOAL : 100  
DIGOAL : 99  
DIGOAL : 88  
DIGOAL : 77  
DIGOAL : 66  
DIGOAL : 55  
DIGOAL : 44  
DIGOAL : 1604442516  
DIGOAL : 4195328  
DIGOAL : 105026360  
// args=10, 实际...里面有7个参数, 所以多打印了3个, 这个是从print_ints这个函数的stack内存区域读出来的值, 没有意义.  

重点 :

va_list ap;  
va_start(ap, name);  
va_arg(ap, 类型);  
va_end(ap);  

例2 :

计算商品总值.

[root@db-172-16-3-150 zzz]# cat a.c  
#include <stdio.h>  
#include <stdarg.h>  
  
typedef enum drink {  
  MUDSLIDE,   
  FUZZY_NAVEL,  
  MONKEY_GLAND,  
  ZOMBIE  
} drink;  
  
double price (drink d) {  
  switch(d) {  
    case MUDSLIDE:  
      return 6.79;  
    case FUZZY_NAVEL:  
      return 5.31;  
    case MONKEY_GLAND:  
      return 4.82;  
    case ZOMBIE:  
      return 5.89;  
  }  
  // others return 0  
  return 0;  
}  
  
double total(int args, ...) {  
  double total = 0;  
  va_list ap;  
  va_start(ap, args);  
  int i;  
  for (i=0; i<args; i++) {  
    enum drink d = va_arg(ap, enum drink);  
    total = total + price(d);  
  }  
  va_end(ap);  
  return total;  
}  
  
  
int main() {  
  fprintf(stdout, "price is %.2f\n", total(2, MUDSLIDE, FUZZY_NAVEL));  
  fprintf(stdout, "price is %.2f\n", total(4, MUDSLIDE, FUZZY_NAVEL, MONKEY_GLAND, ZOMBIE));  
  return 0;  
}  
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g ./a.c -o a && ./a  
price is 12.10  
price is 22.81        

Flag Counter

digoal’s 大量PostgreSQL文章入口