TLPI-Chapter 3系统编程概念
第三章内容概念讲的其实相对好理解,主要有如下几点: /*
* stdarg.h
*
* Provides facilities for stepping through a list of function arguments of
* an unknown number and type.
*
* NOTE: Gcc should provide stdarg.h,and I believe their version will work
* with crtdll. If necessary I think you can replace this with the GCC
* stdarg.h.
*
* Note that the type used in va_arg is supposed to match the actual type
* *after default promotions*. Thus,va_arg (...,short) is not valid.
*
* This file is part of the Mingw32 package.
*
* Contributors:
* Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
*
* THIS SOFTWARE IS NOT COPYRIGHTED
*
* This source code is offered for use in the public domain. You may
* use,modify or distribute it freely.
*
* This code is distributed in the hope that it will be useful but
* WITHOUT ANY WARRANTY. ALL WARRANTIES,EXPRESS OR IMPLIED ARE HEREBY
* DISCLAMED. This includes but is not limited to warranties of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* $Revision: 1.2 $
* $Author: noer $
* $Date: 1998/10/10 00:51:16 $
*
*/
#ifndef _STDARG_H_
#define _STDARG_H_
/*
* Don't do any of this stuff for the resource compiler.
*/
#ifndef RC_INVOKED
/*
* I was told that Win NT likes this.
*/
#ifndef _VA_LIST_DEFINED
#define _VA_LIST_DEFINED
#endif
#ifndef _VA_LIST
#define _VA_LIST
typedef char* va_list;
#endif
/*
* Amount of space required in an argument list (ie. the stack) for an
* argument of type t.
*/
#define __va_argsiz(t)
(((sizeof(t) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))
/*
* Start variable argument list processing by setting AP to point to the
* argument after pN.
*/
#ifdef __GNUC__
/*
* In GNU the stack is not necessarily arranged very neatly in order to
* pack shorts and such into a smaller argument list. Fortunately a
* neatly arranged version is available through the use of __builtin_next_arg.
*/
#define va_start(ap,pN)
((ap) = ((va_list) __builtin_next_arg(pN)))
#else
/*
* For a simple minded compiler this should work (it works in GNU too for
* vararg lists that don't follow shorts and such).
*/
#define va_start(ap,pN)
((ap) = ((va_list) (&pN) + __va_argsiz(pN)))
#endif
/*
* End processing of variable argument list. In this case we do nothing.
*/
#define va_end(ap) ((void)0)
/*
* Increment ap to the next argument in the list while returing a
* pointer to what ap pointed to first,which is of type t.
*
* We cast to void* and then to t* because this avoids a warning about
* increasing the alignment requirement.
*/
#define va_arg(ap,t)
(((ap) = (ap) + __va_argsiz(t)),
*((t*) (void*) ((ap) - __va_argsiz(t))))
#endif /* Not RC_INVOKED */
#endif /* not _STDARG_H_ */
下面我们分别解析每个具体的函数: /* * Amount of space required in an argument list (ie. the stack) for an * argument of type t. */
#define __va_argsiz(t)
(((sizeof(t) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))
#define va_start(ap,pN)
((ap) = ((va_list) (&pN) + __va_argsiz(pN)))
#endif//第一个可选参数地址
/*
* Increment ap to the next argument in the list while returing a
* pointer to what ap pointed to first,t)
(((ap) = (ap) + __va_argsiz(t)),
*((t*) (void*) ((ap) - __va_argsiz(t))))
同样注释部分也说明了,我们指向list中的下一个参数,返回list开始指向的参数. /*
Name: 可变参数
Copyright: 52coder.net
Author: 52coder
Date: 04/09/17 23:44
Description: 可变参数
*/
#include <stdio.h>
#include <stdarg.h>
void print_args(int count,...);
int main(int argc,char* argv[])
{
print_args(5,1,2,3,4,5);
return 0;
}
void print_args(int count,...)
{
int i,value;
va_list arg_ptr;
va_start(arg_ptr,count);
for(i=0; i<count; i++) {
value = va_arg(arg_ptr,int);
printf("position %d = %dn",i+1,value);
}
va_end(arg_ptr);
}
参考例子: /* Name: 可变参数 Copyright: 52coder.net Author: 52coder Date: 04/09/17 23:44 Description: 可变参数 */
#include <stdio.h>
#include <stdarg.h>
double average(int num,...)
{
va_list valist;
double sum = 0.0;
int i;
/* 为 num 个参数初始化 valist */
va_start(valist,num);
/* 访问所有赋给 valist 的参数 */
for (i = 0; i < num; i++)
{
sum += va_arg(valist,int);
}
/* 清理为 valist 保留的内存 */
va_end(valist);
return sum/num;
}
int main()
{
printf("Average of 2,3,4,5 = %fn",average(4,5));
printf("Average of 5,10,15 = %fn",average(3,5,10,15));
}
下面这个例子是征服C指针中的一个例子,我个人认为这个例子非常非常的好。代码如下: #include <stdio.h>
#include <stdarg.h>
#include <assert.h>
void tiny_printf(char * format,...)
{
int i;
va_list ap;
va_start(ap,format);
for(i = 0;format[i]!=' ';i++)
{
switch(format[i])
{
case 's':
printf("%s ",va_arg(ap,char*));
break;
case 'd':
printf("%d ",int));
break;
default:
assert(0);
}
}
va_end(ap);
putchar('n');
}
int main()
{
tiny_printf("sdd","result..",5);
return 0;
}
首先书中从printf入手讲解可变长参数,例如 printf(“%d,%sn”,100,str); 参数压入栈中,不论有多少个参数,第一个参数(指向”%d,%sn”的指针)一定存在于距离固定的场所,如果参数不存入栈,按照从左往右的顺序的话,就不能找到第一个参数。 在代码中利用了assert(0),只要程序经过这里就hi报错,因为我们设计的tiny_printf只能处理s和d类型,用户输入不能输入其它类型。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |