评论

收藏

[C++] 全新版本printf函数你可能没玩过

编程语言 编程语言 发布于:2021-08-06 13:58 | 阅读数:514 | 评论:0

DSC0000.png DSC0001.jpeg C语言可变参数函数C 语言允许定义参数数量可变的函数,这称为可变参数函数。这种函数需要固定数量的强制参数,后面是数量可变的可选参数。这种函数必须至少有一个强制参数。可选参数的类型可以变化。可选参数的数量由强制参数的值决定,或由用来定义可选参数列表的特殊值决定。
C 语言中最常用的可变参数函数例子是 printf()和 scanf()。这两个函数都有一个强制参数,即格式化字符串。格式化字符串中的转换修饰符决定了可选参数的数量和类型。对于每一个强制参数来说,函数头部都会显示一个适当的参数,像普通函数声明一样。参数列表的格式是强制性参数在前,后面跟着一个逗号和省略号(...),这个省略号代表可选参数。
可变参数函数要获取可选参数时,必须通过一个类型为 va_list 的对象,它包含了参数信息。这种类型的对象也称为参数指针(argument pointer),它包含了栈中至少一个参数的位置。可以使用这个参数指针从一个可选参数移动到下一个可选参数,由此,函数就可以获取所有的可选参数。va_list 类型被定义在头文件 stdarg.h 中。

如何实现C语言可变参数通过三个宏(va_start、va_end、va_arg)和一个类型(va_list)实现的

  • void va_start ( va_list ap, paramN );功能:初始化可变参数列表
  • void va_end ( va_list ap );功能:关闭初始化列表(将 ap 置空)。
  • type va_arg ( va_list ap, type );功能:返回下一个参数的值。
好了,综合上面3个宏和一个类型可以猜出如何实现C语言可变长参数函数:
va_start 获取参数列表(的地址)存储到 ap 中,va_arg 逐个获取值,最后用 va_arg 将 ap 置空。

小试牛刀
#include <stdio.h>#include <stdarg.h>#define END -1int va_sum(int first_num, ...){  // (1) 定义参数列表  va_list ap;  // (2) 初始化参数列表  va_start(ap, first_num);  int result = first_num;  int temp = 0;  // 获取参数值  while ((temp = va_arg(ap, int))!=END){    result += temp;  }  // 关闭参数列表  va_end(ap);  return result;}int main(){  printf("%d\n", va_sum(1, 2, 3, 4,END));  printf("%d\n", va_sum(1, 2, 3, 4, 5, END));  return 0;}
注意项

  • 宏定义在 stdarg.h 中,所以使用时,不要忘了添加头文件。
  • 设定一个参数结束标志(cplusplus 上说,va_arg 并不能确定哪个参数是最后一个参数)。
  • 类型的匹配
渐入佳境我们一起来偷看下“内裤”,发现标准库中是这样声明printf函数的。
DSC0002.png

最终你要学习就是这个:int printf(const char * format, ...);下面我们来写一个简单的可变参数的C 函数printf函数
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
int myvfprintf(FILE* stream, const char* format, va_list arglist)
{
int translating = 0;
int ret = 0; //记录最终输出的字符个数
const char* p = 0;
for (p = format; *p != '\0'; ++p)
  {
switch (*p)
    {
case '%':
if (!translating)
      {
        translating = 1; //translating置为1,代表后面的字符需要解析
      }
else
      {
if (fputc('%', stream) < 0)
return EOF;
        ++ret;
        translating = 0;
      }
break;
case 'd':
if (translating) //%d
      {
char buf[16];
        translating = 0;
        _itoa_s(va_arg(arglist, int), buf, 10);
if (fputs(buf, stream) < 0)
return EOF;
        ret += strlen(buf);
      }
else if (fputc('d', stream) < 0)
return EOF;
else
        ++ret;
break;
case 's':
if (translating)
      {
const char* str = va_arg(arglist, const char*);
        translating = 0;
if (fputs(str, stream) < 0)
return EOF;
        ret += strlen(str);
      }
else if (fputc('s', stream) < 0)
return EOF;
else
        ++ret;
break;
default:
if (translating)
        translating = 0;
if (fputc(*p, stream) < 0)
return EOF;
else
        ++ret;
break;
    }
  }
return ret;
}
int myprintf(const char* format, ...)
{
  va_list(arglist);
  va_start(arglist, format);
return myvfprintf(stdout, format, arglist);
}
int main(){
printf("%s\n", "ILoveyou");
  myprintf("%s\n", "ILoveyou");
return 0;
}
运行测试结果:
DSC0003.png


结束语文章都是手打原创,每天最浅显的介绍C语言、C++,windows知识,喜欢我的文章就关注一波吧,每天带你学习C/C++不同的知识,也可以看到最新更新和之前发表的文章哦。如果今天学到知识的,可以在留言区留言学到了哦,如果喜欢可以收藏,转发,评论哦,这真的对我很重要!!


关注下面的标签,发现更多相似文章