valist用法(excel计算总分函数有省略号什么意思) 您所在的位置:网站首页 geomsx valist用法(excel计算总分函数有省略号什么意思)

valist用法(excel计算总分函数有省略号什么意思)

2023-04-18 14:07| 来源: 网络整理| 查看: 265

本文目录excel计算总分函数有省略号什么意思C语言中用函数做函数的形式参数的问题C函数snprintf的用法和避免踩坑C++ 多个函数参数问题c语言用法c语言条件结构代码“va_start(ap,fmt)”是什么意思前面声明过va_list ap;后面出现了va_start (ap, fmt),va_arg (ap, int)fmt 和 int 是什么参数啊C语言的变参技术,va_start,va_arg,va_end这几个函数怎么用va_start va_end的用法excel计算总分函数有省略号什么意思

这个是可变参数的用法。va_list相关一般包含以下4个操作:va_listXX//设定传入的参数的指针。va_start//初始化参数指针。va_arg//通过栈操作,根据偏移量读取参数值。va_end//参数读取完毕。va_start(pArgList,szFormat)。上面的szFormat就是初始的栈指针位置(第一个可变参数的首地址),以他为基准,进行偏移。

C语言中用函数做函数的形式参数的问题

※※※※※※※※※※※第一个问题的答复※※※※※※※※※※※※※※※看明白了你的意思, 其实不知道你自己有没有注意到,你所尝试的方法, 如果用C语言来做的话,其实就是实现了C语言的部分面向对象的实现, 说是“部分“的原因是,这仅仅是实现了面向对象的“方法”。 如果想实现的话,准确的讲,应该不是你所说的,将“函数“作为形参, 应该是将“函数指针”作为形参。 这个在回调(CallBack)函数设计时,使用的非常多, 简单举一个例子: #include 《stdlib.h》 #include 《stdio.h》 int Do1() { return 0; } int Do2(int num) { printf(“The num is: %d\n“, num); return 0; } void CallBack1(void (*ptr)())//指向函数的指针作函数参数 { (*ptr)(); } void CallBack2(int n, int (*ptr)())//指向函数的指针作函数参数,这里第一个参数是为指向函数的指针服务的, { //不能写成void Caller2(int (*ptr)(int n)),这样的定义语法错误。 (*ptr)(n); return; } int main() { CallBack1(Do1); //相当于调用Do1(); CallBack2(50, Do2); //相当于调用Do2(50); return 0; } ※※※※※※※※※※※第一个问题的答复※※※※※※※※※※※※※※※※※※※※※※※※※※补充问题的答复※※※※※※※※※※※※※※※针对你的补充问题,解答如下: 这个是可变形参的实现,准确地说,不是通过数组实现的,而是通过栈实现的。 C语言中的printf,scanf就是最常见的可变形参函数,定义一个可变形参的函数很简单,如void print(int n, ...) ,函数中对参数的处理主要是通过对栈进行操作,而c函数的实参都是自右向左压入栈的. 主要的栈操作(都是宏)有va_list,va_start ,va_arg,va_end, 定义如下: typedef char * va_list; #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) #define va_start _crt_va_start #define va_arg _crt_va_arg #define va_end _crt_va_end #define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) ) #define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) #define _crt_va_end(ap) ( ap = (va_list)0 ) va_start(ap,v):主要是获取可变参数列表的首地址,然后赋值给ap,近似ap=&v+sizeof(v) (这里暂不考虑内存对齐和类型转换) va_arg(ap,t):取得返回类型t的可变参数值, 并使ap指向下一个参数: ap += sizeof(t),这里的t是可变参数的数据类型,如int,float之类 va_end(ap):给ap初始化 va_start(ap,v) va_arg(ap,t) va_end(ap)三者合用,保证程序的健壮性. 一个使用可变形参的简单程序: #include 《stdio.h》 #include 《stdarg.h》 //包含va_list等定义 float sum( float first, ... ) //,...代表可变形参函数 { float i=first,sum=0; va_list maker; //va_list 类型数据可以保存函数的所有参数,做为一个列表一样保存 va_start(maker,first); //设置列表的起始位置 while(i!=-1.0) { sum+=i; i=va_arg(maker,float); //返回maker列表的当前值,并指向列表的下一个位置 } return sum; } void main(void) { printf( “sum is: %f\n“, sum( 2.0,8.0,8.5,-1.0 ) ); //函数调用 }※※※※※※※※※※※补充问题的答复※※※※※※※※※※※※※※※

C函数snprintf的用法和避免踩坑

snprintf 函数是C语言中非常常用的一个函数,它的作用是格式化一段文本放到指定的缓存中。和它类似的还有sprintf, vsnprintf等。它们都完成类似的功能,但又有些区别,如sprintf 是不会检查输出缓存的长度的,需要调用者确保长度是足够的。vsnprintf 函数和snprintf 很像,但它是通过 va_list 来传入格式化参数,所以一般用于传入了可变的需要格式化字符串的函数内。而我们最常用的就是snprintf 了,因为它具有缓冲区的溢出保护。 snprintf函数的原型如下:

其中: str 传入输出缓冲区的地址;size指出输出缓冲区的大小;format 为传入的格式化字符串;其后的参数就是格式化的参数了。

该函数返回一个整数,表示格式化后的文本大小。通过这个返回值,我们可以做很多事情。也正是对这个返回值的理解不够或者使用错误,我们往往会踩一些坑。 最普通的用法是使用该函数来格式化一段文本,如: 该函数具有缓冲区保护的功能,如果格式化输出内容超过了缓冲区的最大长度,那么输出字符串会被截断到缓冲区的最大长度。同时无论如何,字符串最后的结尾 ‘’ 是一定会有的,保证了输出的字符串不会溢出。所以这也是广大程序员喜欢使用这个函数的原因。 如果我们需要格式化一个具有多个元素的数组,那么这个时候就可以充分利用snprintf的返回值了。我们只需要反复调用snprintf 并移动缓冲区的起始位置就能实现。代码如下: 这段代码看起来能正常工作,通常也确实可以正常工作,但是前提条件是 szText的缓冲区大小是足够大的。如果缓冲区的大小不够会发生什么情况?你不妨改小szText再试试。 那么为什么会出现问题呢?首先我们要深入理解一下snprintf 返回值的含义。按前面所述,返回值表示格式化后文本的大小,注意不是返回输出缓冲内的字符串长度。什么意思呢,也就是说,如果输出的缓冲足够大,大到可以容纳所有的输出文本,那么这个返回的长度恰恰就是输出缓存中的字符串长度。如果输出缓冲不够大,或者根本就没有传入输出缓冲这个参数呢?返回值就和实际的输出文本长度不一样了。为什么是这样?其实这个函数本来也是可以用来计算格式化所需要的最小缓存大小,并根据返回值来实际分配输出缓冲的内存。如下代码所示的用法:

有人会疑惑,为什么需要这样写?上面这个例子可能不明显。但是如果需要格式化的内容不固定,长度变化范围很大。那么就有可能不太好使用固定大小的缓冲。 理解了这个返回值的含义和用法,再回到上面那个循环调用的例子。我们需要加上对长度的校验就没有问题了: 如果有什么疑问,欢迎一起讨论。

C++ 多个函数参数问题

可变参数即表示参数个数可以变化,可多可少,也表示参数的类型也可以变化,可以是int,double还可以是char*,类,结构体等等。可变参数是实现printf(),sprintf()等函数的关键之处,也可以用可变参数来对任意数量的数据进行求和,求平均值带来方便(不然就用数组或每种写个重载)。在C#中有专门的关键字parame,但在C,C++并没有类似的语法,不过幸好提供这方面的处理函数,本文将重点介绍如何使用这些函数。

第一步 可变参数表示用三个点…来表示,查看printf()函数和scanf()函数的声明:int printf(const char *, ...);int scanf(const char *, ...);这三个点用在宏中就是变参宏(Variadic Macros),默认名称为__VA_ARGS__。如:#define WriteLine(...) { printf(__VA_ARGS__); putchar(’\n’);}再WriteLine(“MoreWindows“);考虑下printf()的返回值是表示输出的字节数。将上面宏改成:#define WriteLine (...) printf(__VA_ARGS__) + (putchar(’\n’) != EOF ? 1: 0);这样就可以得到WriteLine宏的返回值了,它将返回输出的字节数,包括最后的’\n’。如下例所示i和j都将输出12。 int i = WriteLine(“MoreWindows“); WriteLine(“%d“, i); int j = printf(“%s\n“, “MoreWindows“); WriteLine(“%d“, j);

第二步 如何处理va_list类型函数内部对可变参数都用va_list及与它相关的三个宏来处理,这是实现变参参数的关键之处。在《stdarg.h》中可以找到va_list的定义:typedef char * va_list;再介绍与它关系密切的三个宏要介绍下:va_start(),va_end()和va_arg()。同样在《stdarg.h》中可以找到这三个宏的定义:#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )#define va_end(ap) ( ap = (va_list)0 )#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )其中用到的_INTSIZEOF宏定义如下:#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )来分析这四个宏:va_end(ap)这个最简单,就是将指针置成NULL。va_start(ap,v)中ap = (va_list)&v + _INTSIZEOF(v)先是取v的地址,再加上_INTSIZEOF(v)。_INTSIZEOF(v)就有点小复杂了。( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )全是位操作,看起来有点麻烦,其实不然,非常简单的,就是取整到sizeof(int)。比如sizeof(int)为4,1,2,3,4就取4,5,6,7,8就取8。对x向n取整用C语言的算术表达就是((x+n-1)/n)*n,当n为2的幂时可以将最后二步运算换成位操作——将最低 n - 1个二进制位清 0就可以了。va_arg(ap,t)就是从ap中取出类型为t的数据,并将指针相应后移。如va_arg(ap, int)就表示取出一个int数据并将指针向移四个字节。因此在函数中先用va_start()得到变参的起始地址,再用va_arg()一个一个取值,最后再用va_end()收尾就可以解析可变参数了。

第三步 vfprintf()函数和vsprintf()函数vfprintf()这个函数很重要,光从名字上看就知道它与经常使用的printf()函数有很大的关联。它有多个重载版本,这里讲解最常用的一种:函数原型int vfprintf( FILE *stream, const char *format, va_list argptr);第一个参数为一个FILE指针。FILE结构在C语言的读写文件必不可少。要对屏幕输出传入stdout。第二个参数指定输出的格式。第三个参数是va_list类型,这个少见,但其实就是一个char*表示可变参参数的起始地址。返回值:成功返回输出的字节数(不包括最后的’\0’),失败返回-1。vsprintf()与上面函数类似,就只列出函数原型了:int vsprintf( char *buffer, const char *format, va_list argptr);还有一个int _vscprintf(const char *format, va_list argptr );可以用来计算vsprintf()函数中的buffer字符串要多少字节的空间。代码范例下面就给出了自己实现的printf()函数(注1)与WriteLine()函数int Printf(char *pszFormat, ...) { va_list pArgList;

va_start(pArgList, pszFormat); int nByteWrite = vfprintf(stdout, pszFormat, pArgList); va_end(pArgList);

return nByteWrite;}

int WriteLine(char *pszFormat, ...){ va_list pArgList;

va_start(pArgList, pszFormat); int nByteWrite = vfprintf(stdout, pszFormat, pArgList); if (nByteWrite != -1) putchar(’\n’); //注2 va_end(pArgList);

return (nByteWrite == -1 ? -1 : nByteWrite + 1);}调用与printf()函数相同。再给出一个用可变参数来求和,遗憾的在C,C++中无法确定传入的可变参数的个数(printf()中是通过扫描’%’个数来确实参数的个数的),因此要么就要指定个数,要么在参数的最后要设置哨兵数值:设置哨兵数值:const int GUARDNUMBER = 0; //哨兵标识//变参参数的个数无法确定,在printf()中是通过扫描’%’个数,在这通过设置哨兵标识来确定变参参数的终止int MySum(int i, ...){ int sum = i; va_list argptr;

va_start(argptr, i); while ((i = va_arg(argptr, int)) != GUARDNUMBER) sum += i; va_end(argptr);

return sum;}可以这样的调用: printf(“%d\n“, MySum(1, 3, 5, 7, 9, 0));但不可以直接传入一个0: printf(“%d\n“, MySum(0)); //error指定个数:int MySum(int nCount, ...){ if (nCount 《= 0) return 0;

int sum = 0; va_list argptr;

va_start(argptr, nCount); for (int i = 0; i 《 nCount; i++) sum += va_arg(argptr, int); va_end(argptr);

return sum;}调用时第一个参数表示后面参数的个数如: printf(“%d\n“, MySum(5, 1, 3, 5, 7, 9)); printf(“%d\n“, MySum(0));代码所用的头文件:#include 《stdarg.h》#include 《stdio.h》

可变参数的使用方法远远不止上述几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃。

c语言用法

C语言变参技术概述C语言中有一种长度不确定的参数,形如:“…“,它主要用在参数个数不确定的函数中,我们最容易想到的例子是printf函数。原型:int printf( const char *format ... ); 使用例:printf(“Enjoy yourself everyday!\\n“);printf(“The value is %d!\\n“, value); 这种可变参数可以说是C语言一个比较难理解的部分,这里会由几个问题引发一些对它的分析。注意:在C++中有函数重载(overload)可以用来区别不同函数参数的调用,但它还是不能表示任意数量的函数参数。问题:printf的实现请问,如何自己实现printf函数,如何处理其中的可变参数问题? 答案与分析:在标准C语言中定义了一个头文件《stdarg.h》专门用来对付可变参数列表,它包含了一组宏,和一个va_list的typedef声明。一个典型实现如下:typedef char* va_list;#define va_start(list) list = (char*)&va_alist#define va_end(list)#define va_arg(list, mode)\\((mode*) (list += sizeof(mode))) 自己实现printf:#include 《stdarg.h》int printf(char* format, …){va_list ap;va_start(ap, format);int n = vprintf(format, ap);va_end(ap);return n;} 问题:运行时才确定的参数有没有办法写一个函数,这个函数参数的具体形式可以在运行时才确定?答案与分析:目前没有“正规“的解决办法,不过独门偏方倒是有一个,因为有一个函数已经给我们做出了这方面的榜样,那就是main(),它的原型是:int main(int argc,char *argv); 函数的参数是argc和argv。深入想一下,“只能在运行时确定参数形式“,也就是说你没办法从声明中看到所接受的参数,也即是参数根本就没有固定的形式。常用的办法是你可以通过定义一个void*类型的参数,用它来指向实际的参数区,然后在函数中根据根据需要任意解释它们的含义。这就是main函数中argv的含义,而argc,则用来表明实际的参数个数,这为我们使用提供了进一步的方便,当然,这个参数不是必需的。虽然参数没有固定形式,但我们必然要在函数中解析参数的意义,因此,理所当然会有一个要求,就是调用者和被调者之间要对参数区内容的格式,大小,有效性等所有方面达成一致,否则南辕北辙各说各话就惨了。问题:可变长参数的传递有时候,需要编写一个函数,将它的可变长参数直接传递给另外的函数,请问,这个要求能否实现?答案与分析:目前,你尚无办法直接做到这一点,但是我们可以迂回前进,首先,我们定义被调用函数的参数为va_list类型,同时在调用函数中将可变长参数列表转换为va_list,这样就可以进行变长参数的传递了。看如下所示:void subfunc (char *fmt, va_list argp){...arg = va_arg (fmt, argp); /* 从argp中逐一取出所要的参数 */...}void mainfunc (char *fmt, ...){va_list argp;va_start (argp, fmt); /* 将可变长参数转换为va_list */subfunc (fmt, argp); /* 将va_list传递给子函数 */va_end (argp);...} 问题:可变长参数中类型为函数指针我想使用va_arg来提取出可变长参数中类型为函数指针的参数,结果却总是不正确,为什么?答案与分析:这个与va_arg的实现有关。一个简单的、演示版的va_arg实现如下:#define va_arg(argp, type) \\(*(type *)(((argp) += sizeof(type)) - sizeof(type))) 其中,argp的类型是char *。如果你想用va_arg从可变参数列表中提取出函数指针类型的参数,例如int (*)(),则va_arg(argp, int (*)())被扩展为:(*(int (*)() *)(((argp) += sizeof (int (*)())) -sizeof (int (*)()))) 显然,(int (*)() *)是无意义的。解决这个问题的办法是将函数指针用typedef定义成一个独立的数据类型,例如:typedef int (*funcptr)(); 这时候再调用va_arg(argp, funcptr)将被扩展为:(* (funcptr *)(((argp) += sizeof (funcptr)) - sizeof (funcptr))) 这样就可以通过编译检查了。问题:可变长参数的获取有这样一个具有可变长参数的函数,其中有下列代码用来获取类型为float的实参:va_arg (argp, float); 这样做可以吗?答案与分析:不可以。在可变长参数中,应用的是“加宽“原则。也就是float类型被扩展成double;char,short被扩展成int。因此,如果你要去可变长参数列表中原来为float类型的参数,需要用va_arg(argp,double)。对char和short类型的则用va_arg(argp, int)。问题:定义可变长参数的一个限制为什么我的编译器不允许我定义如下的函数,也就是可变长参数,但是没有任何的固定参数?int f (...){...} 答案与分析:不可以。这是ANSI C 所要求的,你至少得定义一个固定参数。这个参数将被传递给va_start(),然后用va_arg()和va_end()来确定所有实际调用时可变长参数的类型和值。

c语言条件结构

要大致了解下scanf函数。#include《stdio.h》intscanf(constchar*format,va_list);功能:格式化输入或扫描(scanformat=Formattingscanning)。在format串的控制下,读取输入转换并赋值到后面对应的参数变量中。返回值:正确赋值给va_list中变量的输入项目的个数。说明:你的一个例子说明:scanf(“%d“,&c)中的“%d“(d=decimal,十进制数)是一个转换说明符,告诉scanf,把输入文本中匹配整数格式的部分解释成一个基本整数,然后写到c变量中。如果存在某种错误,行为未定义。你可以试验下:intc=7;//定义一个名为x的整数变量,初始值为7intcount;count=scanf(“%d“,&c);//输入格式必须为:数字,用正则描述是:/^+$/printf(“%d“,c);printf(“%d“,count);运行这段代码,会发现,如果你的输入是不正确的数字格式例如包含字母字符,那么输出就不会等于输入的内容,而等于c原先的值。显然,完成相等值判断的if-elseif-else中的else语句肯定会执行。另外这句:printf(“%d“,count)会打印出正确赋值给va_list中变量的输入项目数,所以输入了字母就为0,否则为1。如果那段代码是别人的例子,要做的功能正是如此么。。:当用户的输入不合法时打印提示“pleaseinput“重新输入,直到用户输入了一个合适的数字。

代码“va_start(ap,fmt)”是什么意思

VA_LIST 是在C语言中解决变参问题的一组宏,在《stdarg.h》头文件下。

VA_LIST的用法:      

首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针,然后用VA_START宏初始化变量刚定义的VA_LIST变量,这个宏的第二个参数是第一个可变参数的前一个参数,是一个固定的参数。

然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型。最后用VA_END宏结束可变参数的获取。然后你就可以在函数里使用第二个参数了。如果函数有多个可变参数的,依次调用VA_ARG获取各个参数。

VA_LIST在编译器中的处理:

在运行VA_START(ap,v)以后,ap指向第一个可变参数在堆栈的地址。VA_ARG()取得类型t的可变参数值,在这步操作中首先apt = sizeof(t类型),让ap指向下一个参数的地址。然后返回ap-sizeof(t类型)的t类型*指针,这正是  第一个可变参数在堆栈里的地址。然后用*取得这个地址的内容。

VA_END(),X86平台定义为ap = ((char*)0),使ap不再指向堆栈,而是跟NULL一样,有些直接定义为((void*)0),这样编译器不会为VA_END产生代码,例如gcc在Linux的X86平台就是这样定义的。

要注意的是:由于参数的地址用于VA_START宏,所以参数不能声明为寄存器变量,或作为函数或数组类型。

前面声明过va_list ap;后面出现了va_start (ap, fmt),va_arg (ap, int)fmt 和 int 是什么参数啊

给个例子自己看: 四个重要的宏: va_list va_start va_arg va_endva_list 定义了参数列表va_start 指定列表开始的参数va_arg 取出列表中的参数, 顺序为函数传递参数顺序(从左到右)va_end 参数列表结束举例:#include 《iostream》#include 《stdarg.h》using namespace std;int add(int totalnum...)//totalnum指定了参数的个数,...表示参数不定, 为定义此类函数必需{va_list intlist;//定义参数表 intlistva_start(intlist, totalnum);//指定开始参数为totalnumint totaladd = 0;for(int i=0;i《totalnum;i++){totaladd += va_arg(intlist,int);//取出参数类型为int的参数 你说的fmt是参数的类型如float等}va_end(intlist);//参数取完return totaladd;}void main(){cout《《add(5,1,2,3,4,5)《《endl;}答案为15

C语言的变参技术,va_start,va_arg,va_end这几个函数怎么用

#include 《stdarg.h》 // 必须包含的头文件int Add(int start,...) // ...是作为占位符{ va_list arg_ptr; // 定义变参起始指针 int sum=0; // 定义变参的和 int nArgValue =start; // va_start(arg_ptr,start); // arg_ptr指向第一个变参 do { sum+=nArgValue; // 求和 nArgValue = va_arg(arg_ptr,int); // arg_ptr指向下一个变参 } while(nArgValue != 0); // 判断结束条件;结束条件是自定义为=0时结束 va_end(arg_ptr); // 复位指针 return sum; }函数的调用方法为Add(1,2,3,0);这样,必须以0结尾,因为变参函数结束的判断条件就是读到0停止。解释:所使用到的宏: void va_start( va_list arg_ptr, prev_param ); type va_arg( va_list arg_ptr, type ); void va_end( va_list arg_ptr ); typedef char * va_list; #define _INTSIZEOF(n) ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) #define va_end(ap) ( ap = (va_list)0 )1、首先把va_list被定义成char*,这是因为在我们目前所用的PC机上,字符指针类型可以用来存储内存单元地址。而在有的机器上va_list是被定义成void*的 2、定义_INTSIZEOF(n)主要是为了某些需要内存的对齐的系统.这个宏的目的是为了得到最后一个固定参数的实际内存大小。在我的机器上直接用sizeof运算符来代替,对程序的运行结构也没有影响。(后文将看到我自己的实现)。 3、va_start的定义为 &v+_INTSIZEOF(v) ,这里&v是最后一个固定参数的起始地址,再加上其实际占用大小后,就得到了第一个可变参数的起始内存地址。所以我们运行va_start(ap, v)以后,ap指向第一个可变参数在的内存地址,有了这个地址,以后的事情就简单了。这里要知道两个事情: ⑴在intel+windows的机器上,函数栈的方向是向下的,栈顶指针的内存地址低于栈底指针,所以先进栈的数据是存放在内存的高地址处。 (2)在VC等绝大多数C编译器中,默认情况下,参数进栈的顺序是由右向左的,因此,参数进栈以后的内存模型如下图所示:最后一个固定参数的地址位于第一个可变参数之下,并且是连续存储的。 |--------------------------| | 最后一个可变参数 | -》高内存地址处 |--------------------------| |--------------------------| | 第N个可变参数 | -》va_arg(arg_ptr,int)后arg_ptr所指的地方, | | 即第N个可变参数的地址。 |--------------- | |--------------------------| | 第一个可变参数 | -》va_start(arg_ptr,start)后arg_ptr所指的地方 | | 即第一个可变参数的地址 |--------------- | |------------------------ --| | | | 最后一个固定参数 | -》 start的起始地址 |-------------- -| ................. |-------------------------- | | | |--------------- | -》 低内存地址处 (4) va_arg():有了va_start的良好基础,我们取得了第一个可变参数的地址,在va_arg()里的任务就是根据指定的参数类型取得本参数的值,并且把指针调到下一个参数的起始地址。 因此,现在再来看va_arg()的实现就应该心中有数了: #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) 这个宏做了两个事情, ①用用户输入的类型名对参数地址进行强制类型转换,得到用户所需要的值 ②计算出本参数的实际大小,将指针调到本参数的结尾,也就是下一个参数的首地址,以便后续处理。 (5)va_end宏的解释:x86平台定义为ap=(char*)0;使ap不再 指向堆栈,而是跟NULL一样.有些直接定义为((void*)0),这样编译器不会为va_end产生代码,例如gcc在linux的x86平台就是这样定义的. 在这里大家要注意一个问题:由于参数的地址用于va_start宏,所以参数不能声明为寄存器变量或作为函数或数组类型. 关于va_start, va_arg, va_end的描述就是这些了,我们要注意的 是不同的操作系统和硬件平台的定义有些不同,但原理却是相似的.

va_start va_end的用法

大哥,你审题不仔细,被骗了~~~~~for(;i;i&=i-1);//注意:这个语句后面有一个;,也就是说是个闭循环所以++k也就是在for(;j《n;++j)每完成一个循环后加1,for(;j《n;++j){ //这里循环两轮对吧,j=1和2。你自己都算出来,这个循环循环两次,所以k最后为2



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有