pic
一、合租国外主机现状 众所周知,国外主机空间一般都很大,流量等限制少,域名绑定不限,故很多人想合租国外主机,或者将自己买的主机拿出去卖。 朋友合租。这类一般是几个朋友合伙买一个国外空间,每个人分一个FTP,由大家共同管理,共同约定。缺点是管理不健全,很容易对其他人网站造成影响,故只建议熟识的朋友几个人一起用,相互之间有足够的信任。 Share Hosting合租。这类是我很反对的,因为Share Hosting的CPU,内存和I/O等资源限额...
pic
刚不久发表的一篇  [揭秘美国主机代购、美国主机评测等类似网站的赚钱方式]的文章,闲逛Ubuntu中文论坛,发现Ubuntu中文论坛也搞起了美国主机代购。详情点击。 Ubuntu中文论坛也是使用burstnet的vps主机,正因为这样,它才有说服力,用户完全可以通过ubuntu论坛得知此vps的性能。但Hector感觉此vps的速度不咋地。。而ubuntu的名气也足以使大家相信此vps不是骗人的。而且此vps相当便宜,最常用的一个vps信息如下: VPS #1 (Virtual Private Server) - vePortal - CPU: 1GH...
pic
一、写在前面 现在网上有大量的美国主机导购网站,美国主机评测网站,上面有各个美国主机提供商的中文翻译信息,选购指南,优惠码信息,各种使用技巧等等。他们确实让广大想到国外买主机的用户得到了大量的信息,甚至还愿意帮用户买相应的美国主机。其目的何在?其利润何在?今天Hector就来分析分析他们的盈利方式。 二、美国主机的Resellers Plan(经销商计划) 计划每个美国主机网站都有自己的一套经销商计划,其方式可能不同,都是...
pic
首先申明,此文章没有任何价值,就是想看看我能不能制造一个网络流行语啥的(当然现在在百度,google上搜不到类似的信息下面有图为证)。这句话可以组成很多经典的句子,我先来两个,如果你有兴趣的可以在下面跟几条经典的。1、在这天朝的年代,竟有google这个二愣子的存在。2、在这如此文明的年代,竟有叫兽如此猥琐的存在。3、在这如此纯洁的年代,竟有XX门和XX门的存在。4、在这如此低调的年代,竟有凤姐的存在。5、在这乙肝遭歧视的年...
pic
一、GFW的名称 GFW 并非官方的正式名称 墙 防火长城 长城防火墙 中国国家防火墙 国家公共网络监控系统 功夫网(Gong Fu Wang) 二、GFW简介 GFW是架设在中国主干级网路路由器上的一套高级资讯过滤系统,主要用途是对境内外网路的访问分析和过滤,阻止用户浏览政府不希望用户看到的网页内容、电邮等资讯。据一项哈佛大学的一项研究,有超过18000个网站在中国境内被 GFW 屏蔽。 GFW的全写为「Great FireWall」,得名于Charles R. Smith所写的一篇...

25

stdarg.h—-函数参数个数不确定时的用法
Posted on : 25-06-2009 | By : Hector | In : 编程杂谈
0

今天写数组的数据结构时,看到了函数参数不确定头文件stdarg.h的一些用法,典型的例子有大家熟悉的函数printf()、scanf()和系统调用execl()等,那么它们是怎样实现的呢?
 

现在先用一个使用过程讲解一下:

◎用法:
func( Type para1, Type para2, Type para3, … )
{
/****** Step 1 ******/
va_list ap;
va_start( ap, para3 ); //一定要“…”之前的那个参数 ,而且这个参数不能使引用类型,因为引用类型不能根据其地址获取后面参数的地址

/****** Step 2 ******/
//此时ap指向第一个可变参数
//调用va_arg取得里面的值

Type xx = va_arg( ap, Type );

//Type一定要相同,如:
//char *p = va_arg( ap, char *);
//int i = va_arg( ap, int );

//如果有多个参数继续调用va_arg

/****** Step 3 ******/
va_end(ap); //For robust!
}
然后写个小程序,大家看看就明白了stdarg.h的用法了

 

#include <iostream>
#include <stdarg.h>
const int N=5;
using namespace std;
void Stdarg(int a1,…)
{
    va_list argp;
    int i;
    int  ary[N];
    va_start(argp,a1);
    ary[0]=a1;
    for(i=1;i< N;i++)
       ary[i]=va_arg(argp,int);
    va_end(argp);
    for(i=0;i< N;i++)
       cout<<ary[i]<<endl;
}
void main()
{
    Stdarg(5,12,64,34,23);
}

最后我们来分析一下stdarg.h这个头文件(呵呵,本人也是看的不太懂)

typedef char * va_list;

#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_list argptr;
C语言的函数是从右向左压入堆栈的,调用va_start后,
按定义的宏运算,_ADDRESSOF得到v所在的地址,然后这个
地址加上v的大小,则使ap指向第一个可变参数如图:

栈底 高地址
| …….
| 函数返回地址
| …….
| 函数最后一个参数
| ….
| 函数第一个可变参数 <–va_start后ap指向
| 函数最后一个固定参数
| 函数第一个固定参数
栈顶 低地址

然后,用va_arg()取得类型t的可变参数值, 先是让ap指向下一个参数:
ap += _INTSIZEOF(t),然后在减去_INTSIZEOF(t),使得表达式结果为
ap之前的值,即当前需要得到的参数的地址,强制转换成指向此参数的
类型的指针,然后用*取值

最后,用va_end(ap),给ap初始化,保持健壮性。

example:(chenguiming)

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

int average( int first, … ) //变参数函数,C++里也有
{
int count=0,i=first,sum=0;
va_list maker; //va_list 类型数据可以保存函数的所有参数,做为一个列表一样保存
va_start(maker,first); //设置列表的起始位置
while(i!=-1)
{
sum+=i;
count++;
i=va_arg(maker,int);//返回maker列表的当前值,并指向列表的下一个位置
}
return sum/count;

}

void main(void)
{
printf( "Average is: %d\n", average( 2, 3, 4,4, -1 ) );
}

Linux下的stdarg.h

#ifndef _STDARG_H
#define _STDARG_H

typedef char *va_list; /* 定义va_list 是一个字符指针类型*/

/* Amount of space required in an argument list for an arg of type TYPE.
TYPE may alternatively be an expression whose type is used. */
/* 下面给出了类型为TYPE 的arg 参数列表所要求的空间容量。
TYPE 也可以是使用该类型的一个表达式 */

// 下面这句定义了取整后的TYPE 类型的字节长度值。是int 长度(4)的倍数。
#define __va_rounded_size(TYPE) \
(((sizeof (TYPE) + sizeof (int) – 1) / sizeof (int)) * sizeof (int))

// 下面这个函数(用宏实现)使AP 指向传给函数的可变参数表的第一个参数。
// 在第一次调用va_arg 或va_end 之前,必须首先调用该函数。
// 17 行上的__builtin_saveregs()是在gcc 的库程序libgcc2.c 中定义的,用于保存寄存器。
// 它的说明可参见gcc 手册章节“Target Description Macros”中的
// “Implementing the Varargs Macros”小节。
#ifndef __sparc__
#define va_start(AP, LASTARG) \
(AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
#else
#define va_start(AP, LASTARG) \
(__builtin_saveregs (), \
AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
#endif

// 下面该宏用于被调用函数完成一次正常返回。va_end 可以修改AP 使其在重新调用
// va_start 之前不能被使用。va_end 必须在va_arg 读完所有的参数后再被调用。
void va_end (va_list); /* Defined in gnulib *//* 在gnulib 中定义 */
#define va_end(AP)

// 下面该宏用于扩展表达式使其与下一个被传递参数具有相同的类型和值。
// 对于缺省值,va_arg 可以用字符、无符号字符和浮点类型。
// 在第一次使用va_arg 时,它返回表中的第一个参数,后续的每次调用都将返回表中的
// 下一个参数。这是通过先访问AP,然后把它增加以指向下一项来实现的。
// va_arg 使用TYPE 来完成访问和定位下一项,每调用一次va_arg,它就修改AP 以指示
// 表中的下一参数。
#define va_arg(AP, TYPE) \
(AP += __va
_rounded_size (TYPE), \
*((TYPE *) (AP – __va_rounded_size (TYPE))))

#endif /* _STDARG_H */
 

这篇日志发表于09年06月25日。 你可以订阅该日志的所有评论通过 RSS 2.0。 你可以发表评论,或者引用通告

Leave a Reply

您可以选择您的最新博文在留言区域显示

最新评论

标签云

© 2010 - IT元素 | Theme AppChain | |