当前位置:网站首页>Appendix A printf, varargs and stdarg a. 2 use varargs. H to realize the variable argument list
Appendix A printf, varargs and stdarg a. 2 use varargs. H to realize the variable argument list
2022-08-01 21:20:00 【weixin_Guest time】
A.2 使用varargs.hto implement a variable parameter list
在编写C程序的过程中,随着程序规模的增大,Programmers often feel the need for systematic error handling.
error("%d is out of bounds", x);
is equivalent to the following
fprintf(stderr, "error: %d is out of bounds\n", x);
exit(1);
只有一个小细节“梗”live with us:errorThe parameters of the function between the number and type in different call is not fixed,而是像
printffunction that may vary from call to call.A typical solution is toerrorThe function is written like the following,Unfortunately, this is not correct:
void error(a, b, c, d, e, f, g, h, i, j, k);
{
fprintf(stderr, "error:");
fprintf(stderr, a, b, c, d, e, f, g, h, i, j, k);
fprintf(stderr, "\n");
exit(1);
}
因为函数a到k并没有声明,So they are by defaultint类型.当然,errorThe function contains at least one non-int类型的参数(即格式字符串).因此,The correct operation of this program depends on whether a set of integer parameters can be used to copy any type of value.
printfThe first parameter of the function must be a string,We can get the number and type of other parameters by examining this string(当然,假定printfThe function call is correct).
为了便于printf函数的实现,Such a mechanism should have the following properties.
*Just need to know the type of the first parameter of the function,can access it.
*一旦第nparameters were successfully accessed,第n+1parameters can be accessed knowing only the type.
*In this way the time needed for access a parameter should not be too much.
需要特别注意的是,reverse access parameter,Or random access parameters,Or access parameters in any non-start-to-finish sequential manner,都是不必要的.进一步来说,Test parameter list whether to end is usually unnecessary,也不可能.
大多数CLanguage implementation are always called through a set ofvarargsMacro definition to achieve the above purpose.Although an exact definition of the macro and specificC语言实现有关,But as long as we use it properly in the program,still be able to use variadic argument lists on quite a few machines.
任何一个程序,只要用到varargs中的宏,就应该像下面这样:
#include<varargs.h>
varargs.hThe macro name is defined in the header fileva_list、va_dcl、va_start、va_end以及va_arg.va_alistUsually defined by the programmer.
任何一个C语言实现中,For the first part of the variable parameter listn个参数,access it when its type is known,Also need some additional information.This information is already accessible through the1个参数到第n-1obtained indirectly from a parameter,Can take it as a pointer to a pointer within the parameter list.当然,The specific implementation may be much more complex on some machines.
This information is stored in a type ofva_list的对象中.因此,When declaring a name forap的类型为va_list的对象后,We just need to giveapwith the type of the first argument,you can determine the value of the first parameter.
通过va_listAfter accessing a parameter,va_list将被更新,指向参数列表中的下一个参数.
因为一个va_listcontains all necessary information to access all parameters,所以函数fYou can create ava_list,and then pass it to another functiong.这样,函数gto access the functionf的参数.
在许多C语言实现中,printfin the family of functions3个函数(printf、fprintf和sprintf),They both call a common subfunction.And for this subfunction,It is important to get the parameters of its calling function.
The called is a function with a variable argument list,Must be used at the beginning of a function definitionva_alist和va_dcl宏,如下所示:
#include<varargs.h>
void error(va_alist) va_dcl
宏va_alistwill expand to a specificCList of parameters required by the implementation,This allows the function to handle variable-length arguments;而宏va_dclwill expand to the declaration corresponding to the parameter list,Include a semicolon as an end-of-statement marker if necessary.
errorThe function must create ava_list变量,Pass the variable name to the macrova_startto initialize the variable.这样做之后,can be read one by oneerrorParameters in the function's parameter list.When the program no longer uses the parameters in the parameter list,我们必须以va_listTo invoke the macro variable named parametersva_end,Indicates that it is no longer necessary to useva_list变量了.
errorThe function is then further extended to:
#include <varargs.h>
void error(va_alist) va_dcl
{
va_list ap;
va_start(ap); //初始化ap变量,may allocate dynamic memory
//这里是使用apThe program part of the
va_end(ap); //free dynamic memory or do nothing
//这里是不使用apother program parts of
}
务必记住,在使用完va_listThe macro must be called after the variableva_end.某些版本的va_startmacro for convenienceva_list进行遍历,Can give a parameter list dynamically allocated memory.这样一种Cimplementation is likely to utilizeva_endmacro to free previously dynamically allocated memory,如果忘记,则会发生“内存泄漏”.
#include <varargs.h>
void error(va_alist) int va_alist;
{
char *ap
ap = (char *)&va_alist;
//这里是使用apThe program part of the
va_end(ap);
//这里是不使用apother program parts of
}
宏va_argto access a parameter.Its two parameters areva_listThe variable name and the type of data you wish to access.va_listThe macro will take this parameter,并更新va_list变量,make it point to the next parameter.
#include <varargs.h>
void error(va_alist) va_dcl
{
va_list ap;
char *format;
va_start(ap);
format = va_arg(ap, char *); //to access a parameter
fprintf(stderr, "error: ");
//(do something magic) //Some implementations are temporarily unknown work
va_end(ap);
fprintf(stderr, "\n") ;
exit(1);
}
#include<varargs.h>
void error(va_alist) int va_alist; {
char *ap;
char *format;
ap = (char *)&va_alist;
format = ((char **)(ap += sizeof(char*)))[-1];
fprintf(stderr, "error: ");
//(do something magic) //Some implementations are temporarily unknown work
va_end(ap);
fprintf(stderr, "\n") ;
exit(1);
}
temporarily blocked:没有办法让printf函数接受一个va_list变量作为参数.
幸运的是,ANSI C标准要求,而且很多CThe language implementation also provides separately calledvprintf、vfprintf和vsprintf的函数.These functions correspond toprintfThe function in the family of functions on the behaviors are exactly the same,只不过用va_listSequence of arguments after replacing the format string.The reason why these functions can exist,理由有两个:其一,va_listVariables can be passed as parameters;其二,va_argMacros can be implemented independently in a function,is not required to beva_start宏(The function of the macro is initializedva_list变量)成对使用.
errorA final version of the function as shown below:
#include <stdio.h>
#include <varargs.h>
void error(va_alist) va_dcl
{
va_list ap;
char *format;
format = va_arg(ap, char *);
fprintf(stderr, "error: ");
vfprintf(stderr, format, ap);
va_end(ap);
fprintf(stderr, "\n");
exit(1);
}
void error(va_alist) int va_alist; {
char *ap;
char *format;
format = ((char **)(ap += sizeof(char*)))[-1];
fprintf(stderr, "error: ");
vfprintf(stderr, format, ap);
va_end(ap);
fprintf(stderr, "\n");
exit(1);
}
保存vprintf函数的结果,We need to return this result toprintf函数的调用方.
#include <varargs.h>
int printf(va_alist) va_dcl {
va_list ap;
char *format;
int n;
va_start(ap);
format = va_arg(ap, char *);
n = vprintf(format, ap);
va_end(ap);
return n;
}
int printf(va_alist) int va_alist {
char *ap;
char *format;
int n;
ap = (char *)&va_alist;
format = ((char **)(ap += sizeof(char *)))[-1];
n = vprintf(format, ap);
va_end(ap);
return n;
}
A.2.1 实现varargs.h
#include <varargs.h>
typedef char *va_list;
#define va_dcl int va_alist;
#define va_start(list) list = (char *)&va_alist;
#define va_end(list)
#define va_arg(list, mode) \
((mode *)(list += sizeof(mode)))[-1]
这个版本中,va_alistnot even a macro:
#include <varargs.h>
void error(va_alist) va_dcl
将扩展为:
typedef char *va_list;
void error(va_alist) int va_alist;
This example actually implies the following assumptions:底层的CThe language requires function arguments to be stored contiguously in memory,So we just need to know the current parameters of address,You can access other parameters in the parameter list in turn.
va_arg:It must return anva_listthe value pointed to by the appropriate type,同时递增va_list,make it point to the next parameter in the parameter list(i.e. the incremented size is equal to andva_argThe value returned by the macro has the length of an object of the same type).because the result of a type conversion cannot be the target of an assignment operation(译注:That is, you can only assign first and then perform type conversion.,instead of type conversion and assignment)
这里有一个“陷阱”需要避免:va_argThe second parameter of the macro cannot be specified aschar、short或float类型.因为char和shortparameters of type are converted toint类型,而float类型的参数被转换为double类型.如果错误地指定了,will cause trouble in the program.
c = va_arg(ap, char); //wrong
会被转换为int类型.
应该写成:
c = va_arg(ap, int);
cp = va_arg(ap, char *); //right
当作为参数时,pointers are not converted,只有char、short和floatvalues of the type will be converted.
我们应该注意到,There is no built-in way to know a given number of arguments.使用varargsEach program of a series of macros,are responsible for marking the end of the parameter list by establishing some convention or convention.
边栏推荐
- JS提升:手写发布订阅者模式(小白篇)
- How to encapsulate the cookie/localStorage sessionStorage hook?
- Graph adjacency matrix storage
- C Pitfalls and pitfalls Appendix B Interview with Koenig and Moo
- C Expert Programming Chapter 1 C: Through the Fog of Time and Space 1.2 Early Experience of C Language
- PyTorch笔记 - Attention Is All You Need (2)
- Day33 LeetCode
- win10版本1803无法升级1903系统如何解决
- 线上一次JVM FullGC搞得整晚都没睡,彻底崩溃~
- C陷阱与缺陷 第8章 建议与答案 8.1 建议
猜你喜欢

An online JVM FullGC made it impossible to sleep all night and completely crashed~

ISC2022 HackingClub白帽峰会倒计时1天!最全议程正式公布!元宇宙集结,精彩绝伦!

Pytorch框架学习记录8——最大池化的使用

线上一次JVM FullGC搞得整晚都没睡,彻底崩溃~

Internet使用的网络协议是什么

牛血清白蛋白刺槐豆胶壳聚糖缓释纳米微球/多西紫杉醇的纳米微球DTX-DHA-BSA-NPs

网络安全与基础设施安全局(CISA):两国将在网络安全方面扩大合作

网红驼背矫正产品真的管用吗?如何预防驼背?医生说要这样做

方舟生存进化是什么游戏?好不好玩

30+的女性测试人面试经验分享
随机推荐
C Expert Programming Preface
Pytorch框架学校记录11——搭建小实战完整细节
shell脚本
ahooks 是怎么处理 DOM 的?
C Expert Programming Chapter 1 C: Through the Fog of Time and Space 1.4 K&R C
C陷阱与缺陷 第7章 可移植性缺陷 7.6 内存位置0
Taobao's API to get the list of shipping addresses
Interview Blitz 70: What are sticky packs and half packs?How to deal with it?
可视化——Superset使用
LeetCode
测试的意义并不是能找到全部的缺陷
C Pitfalls and Defects Chapter 7 Portability Defects 7.11 An Example of a Portability Problem
Questions I don't know in database kernel interview(1)
Transformer学习
C陷阱与缺陷 第7章 可移植性缺陷 7.10 首先释放,然后重新分配
C专家编程 前言
JSD - 2204 - Knife4j framework - processing - Day07 response results
idea实用快捷键合集——持续更新
C Pitfalls and pitfalls Appendix B Interview with Koenig and Moo
JSD-2204-Knife4j框架-处理响应结果-Day07