• 可变参数函数


    背景:

      在我们开发C/C++项目中,经常会使用到系统提供的可变参数函数,例如printf,scanf等。根据需求我们也可能使用到可变参数函数,虽然真正使用的机会不是很多,但是我还是比较好奇如何去实现可变参数函数。这篇博文主要是我记录学习可变参数的一个demo,具体功能是模仿scanf,目前只实现简单的功能,对可变参数函数的一种简单理解。其中使用到这篇博文使用宏实现日志信息以及异常处理。除此之外,我还搜索了几遍博文感觉讲的不错,大家也可以仔细读一读

    Demo:

      1 /** WARNING: this code is fresh and potentially isn't correct yet. */
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 #include <stdarg.h>
      5 #include "dbg.h"
      6 
      7 #define MAX_DATA 100
      8 
      9 int read_string(char **out_string, int max_buffer)
     10 {
     11     *out_string = calloc(1, max_buffer + 1);
     12 
     13     check_mem(*out_string);
     14     char *result = fgets(*out_string, max_buffer, stdin);
     15     check(result != NULL, "Input error.");
     16     return 0;
     17 error:
     18     if(*out_string) free(*out_string);
     19     *out_string = NULL;
     20     return -1;
     21 }
     22 
     23 int read_int(int *out_int)
     24 {
     25     char *input = NULL;
     26     int rc = read_string(&input, MAX_DATA);
     27     check(rc == 0, "Failed to read number.");
     28 
     29     *out_int = atoi(input);
     30     free(input);
     31     return 0;
     32 error:
     33     if(input) free(input);
     34     return -1;
     35 }
     36 
     37 int read_scan(const char *fmt, ...)
     38 {
     39     int i = 0;
     40     int rc = 0;
     41     int *out_int = NULL;
     42     char *out_char = NULL;
     43     char *out_string = NULL;
     44     int max_buffer = 0;
     45     va_list argp;
     46     va_start(argp, fmt);
     47 
     48     for (i = 0; fmt[i] != '\0'; i++) {
     49         if (fmt[i] == '%') {
     50             i++;
     51             switch(fmt[i])
     52             {
     53                 case '\0':
     54                     sentinel("Invalid format, you ended with %%.");
     55                     break;
     56                 case 'd':
     57                     out_int = va_arg(argp, int *);
     58                     rc = read_int(out_int);
     59                     check(rc == 0, "Failed to read int.");
     60                     break;
     61                 case 'c':
     62                     out_char = va_arg(argp, char *);
     63                     *out_char = fgetc(stdin);
     64                     break;
     65                 case 's':
     66                     max_buffer = va_arg(argp, int);
     67                     out_string = va_arg(argp, char **);
     68                     rc = read_string(out_string, max_buffer);
     69                     check(rc == 0, "Failed to read string.");
     70                     break;
     71                 default:
     72                     sentinel("Invalid format.");
     73             }
     74         } else {
     75             fgetc(stdin);
     76         }
     77         check(!feof(stdin) && ! ferror(stdin), "Input error.");
     78     }
     79     va_end(argp);
     80     return 0;
     81 error:
     82     va_end(argp);
     83     return -1;
     84 }
     85 
     86 int main(int argc, char* argv[])
     87 {
     88     char *first_name = NULL;
     89     char initial = ' ';
     90     char *last_name = NULL;
     91     int age = 0;
     92     int age1 = 0;
     93     int age2 = 0;
     94     printf("What's your first name?");
     95     int rc = read_scan("%s", MAX_DATA, &first_name);
     96     check(rc == 0, "Failed first name.");
     97 
     98     printf("What's your initial?");
     99     rc = read_scan("%c\n", &initial);
    100     check(rc == 0, "Failed initial.");
    101 
    102     printf("What's your last name?");
    103     rc = read_scan("%s", MAX_DATA, &last_name);
    104     check(rc == 0, "Failed last name.");
    105 
    106     printf("How old are you?");
    107     rc = read_scan("%d", &age);
    108     check(rc == 0, "Failed age.");
    109 
    110     rc = read_scan("%d%s", &age1, MAX_DATA, &first_name);
    111     check(rc == 0, "Failed more age.");
    112 
    113     printf("-------- RESULT -------\n");
    114     printf("First name: %s", first_name);
    115     printf("Initial: %c\n", initial);
    116     printf("Last name : %s", last_name);
    117     printf("Age: %d\n", age1);
    118 
    119     free(first_name);
    120     free(last_name);
    121     return 0;
    122 error:
    123     return -1;
    124 }

      这个demo主要是简单模拟scanf函数功能。

    看看结果:

     1 zhaoscmatoMacBook-Pro:c zhaosc$ ./ex25
     2 What's your first name?LI
     3 What's your initial?T
     4 What's your last name?Shuchao
     5 How old are you?26
     6 23
     7 Zhaosc
     8 -------- RESULT -------
     9 First name: Zhaosc
    10 Initial: T
    11 Last name : Shuchao
    12 Age: 23

    简单说说:

      首先必须引入头文件stdarg.h,这样才能使用结构体va_list,和宏va_start,va_arg,va_start,va_end,具体每个宏在“读一读”中有详细的说明。这个demo只支持%s,%c和%d,他们可以单独使用也可以组合使用。其中主要处理在read_scan函数中。

  • 相关阅读:
    学习SpringMVC——从HelloWorld开始
    线性队列
    线性表之链表
    线性表之顺序表
    nextSibling 属性与 nextElementSibling 属性的异同
    JavaScript数组增删方法总结
    class关键字
    JS三座大山_单线程&EventLoop
    JS三座大山_闭包
    JS三座大山_原型与原型链
  • 原文地址:https://www.cnblogs.com/zhaosc/p/3079088.html
Copyright © 2020-2023  润新知