C语言中 v...printf类函数的用法

C语言的自学渐渐接近尾声,今天学到了标准库中的stdarg.h头,里面关联了stdio.h头里面的一类函数:v...printf函数,里面举的例子看了之后还是不太明白,google了一下依旧不是很懂,所以自行测试了一下,以下是过程:

这一类函数书中列举了四个,原型分别有:

int vfprintf(FILE *restrict stream, const char * restrict format, va_list arg);

int vprintf(const char * restrict format, va_list arg);

int vsnprintf(char * restrict s, size_t n, const char * restrict format, va_list arg);

int vsprintf(char * restrict s, const char * restrict format, va_list arg);

书中用vfprintf函数举例:

假设程序需要不时地显示出错消息,而且我们希望每条消息都以以下格式的前缀开始:

** Error n:

这里的n在显示第一条出错消息的时候是1,以后每显示一条错误消息增加1。为了使产生出错消息更加容易,我们将编写一个名为errorf的函数。此函数类似于printf函数,但是它总在输出的开始添加了** Error n:,并且总是向stderr而不是stdout输出。errorf函数将调用vfprintf函数来完成大部分实际输出工作。下面是errorf函数可能的写法:

int errorf(const char *format, ...)
{
  static int num_errors = 0;
  int n;
  va_list ap;

  num_errors++;
  fprintf(stderr, "** Error %d: ", num_errors);
  va_start(ap, format);
  n = vfprintf(stderr, format, ap);
  va_end(ap);
  fprintf(stderr, "\n");
  return n;
}

看完例子之后我依然不知道这个函数究竟有什么作用,于是我google了一下,发现了一个网站举了这样一个例子:

/* vfprintf example */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

/* functions */
void inputError(char *function, char *format, ...);

/* main */
int main(void) {
    int sex, age;

    /* 输入性别 */
    puts("请输入性別:(1:男性 2:女性)");
    scanf("%d", &sex);
    if ( sex != 1 && sex != 2 ) {
        inputError("main", "性别是1或2!(输入值: %d)\n", sex);
        return EXIT_FAILURE;
    }

    /* 输入年龄 */
    puts("请输入年龄:");
    scanf("%d", &age);
    if ( age < 0 || age > 150 ) {
        inputError("main", "年龄范围[0,150]!(输入值: %d)\n", age);
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

/**
* @brief 错误处理
* @param[IN] function 函数名
* @param[IN] format 格式化字符串
* @param[IN] ... 可变长参数
*/
void inputError(char *function, char *format, ...) {
    va_list arg;
    va_start(arg, format);

    fprintf(stderr, "发生错误的函数: %s\n", function);

    /* 显示错误信息 */
    vfprintf(stderr, format, arg);

    va_end(arg);
}

执行结果:

请输入性別:(1:男性 2:女性)

3

发生错误的函数: main

性别是1或2!(输入值: 3)

我看完例子之后有点模模糊糊的感觉了,难道说这类函数是将调用它们的函数的可变参数列表转化为自己的可变参数列表,然后通过格式匹配将这些参数输出到流中的?

于是我自己写了个小函数测试一下:

#include<stdio.h>
#include<stdlib.h>
#include<stdarg.h>

int func(char *str, ...)
{
  int n;
  va_list ap;

  va_start(ap, str);
  n = vfprintf(stdout,str,ap);
  va_end(ap);
  return n;
}

int main(void)
{
  func("%d%d\n",2,1);
  return 0;
}

执行的结果为:

21

果然验证了我的想法,看来这一类函数的用法就是利用va_list记录可变参数位置的特性,将母函数的可变参数列表通过va_list变量转化给v...printf函数的,也就是说跟...printf类的函数是一样的,只不过把...printf类函数的可变参数列表省略,替换成从va_list变量调用而已!

时间: 2024-11-03 05:35:44

C语言中 v...printf类函数的用法的相关文章

GO语言中import的规则和用法

GO语言中引入包使用import,我将在本文讲解下规则和用法. 一些规则: 1.包中不能有main方法. 2.同文件夹中可以直接用方法名调用. 3.main函数建议放在package main里4.main不能调用同个目录下的其它文件中的方法. 5.还可以把包放在上级的目录中,如: /src/myFolder/foo/bar1.go #package foo /src/myFolder/foo/bar2.go #package foo /src/myFolder/foo/bar3.go #pac

C++中cout输出字符串和字符串型指针地址值的方法以及C语言中的printf用法比较

#include <iostream> using namespace std; #include <stdio.h> int main() { char *pstr = "china"; char *qstr = "america"; char *q = "adf"; char * s; s = "hello"; printf("pstr = %p\n", pstr); /*输出为

C语言中的printf(),sprintf(),scanf(),sscanf()

在将各种类型的数据构造成字符串时,sprintf 的强大功能很少会让你失望.由于sprintf 跟printf 在用法上几乎一样,只是打印的目的地不同而已,前者打印到字符串中,后者则直接在命令行上输出.这也导致sprintf 比printf 有用得多. printf 语法: #include <stdio.h> int printf( const char *format, ... ); printf()函数根据format(格式)给出的格式打印输出到STDOUT(标准输出)和其它参数中.返回

C 语言中的printf()多参数输出问题

问题: x=1; y=2; printf("%d",x+y,x++,y++); 输出结果为什么是5? 首先解释一点,x+y,x++,y++是逗号表达式,逗号表达式的结果是最后一个表达式的结果. 但是在这里printf()函数是从左往右读取,然后将先读取放到栈底,最后读取的放在栈顶,处理时候是从栈顶开始的,所以我们看见的结果是,从右边开始处理的. 读取入栈:                                                           处理计算:  

C语言中的printf函数的输入输出问题

这个问题是个很基础,但是我一直不知道的问题,是同学问了之后才知道的,长知识了. 这里要注意的是,printf函数是从右向左计算,从左向右输出. 距离如下: #include <stdio.h> main() { int i=8; printf%d, %d, %d, %d\n",i,--i,i,i--); } 此程序输出结果为:7, 7, 8, 8.原因是,printf()函数中,i++,i-- 时,i的值是在printf()函数之后才会被刷新,所以在printf()函数中,i++,i

C语言中mktime函数功能及用法

今天联系写一个日历的程序,需要算出月份中的第一天是星期几,用到了mktime()这个函数,感觉这个函数挺有用的,分享给大家. 原型:time_t mktime(struct tm *) 其中的tm结构体定义如下: struct tm { int tm_sec; /* 秒 – 取值区间为[0,59] */ int tm_min; /* 分 - 取值区间为[0,59] */ int tm_hour; /* 时 - 取值区间为[0,23] */ int tm_mday; /* 一个月中的日期 - 取值

C语言中的strstr函数的用法

strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串.如果是,则该函数返回str2在str1中首次出现的地址:否则,返回NULL. PHP语言函数 编辑 strstr() 函数搜索一个字符串在另一个字符串中的第一次出现. 该函数返回字符串的其余部分(从匹配点).如果未找到所搜索的字符串,则返回 false. 语法 1 strstr(string,search) [1] 参数 描述 string 必需.规定被搜索的字符串. search 必需.规定所搜索的字符串. 提

[原创]c语言中const与指针的用法

最近一直在准备笔试,补补大一大二欠下的课.复习c语言时碰见这么个题: 1 2 3 4 5 int a=248, b=4; int const c=21; const int *d=&a;  int *const e=&b; int const * const f =&a;  请问下列表达式哪些会被编译器禁止? A:*c=32 B:*d=43 C:e=&a D:f=0x321f E:d=&b F:*e=34 下面逐条分析第一行代码不提, 第二行,int const c

Objective-C语言中的Block简介以及用法.

Block语法是在iOS4.0的SDK 中开始新增的, 在那时就已经有了超过400多个API使用了Block语法. Block对象又同样是继承与NSObject, 是C语言级别的语法和运行时特性. 和标准的C函数指针类似. 但其除了可执行语句外, 还可以类似对象可以保持状态数据. 和C语言的函数指针类似, 但不完全相同. 常用来作为回调函数使用. Block和函数的操作符对比: 函数指针使用的是 ‘*’ Block使用的是 ‘^’ 下面是例子: apple.h文件 #import <Founda