- 浏览: 886098 次
- 性别:
- 来自: 太原
文章分类
- 全部博客 (198)
- Linux/Unix (38)
- TinyOS / NS-2 for『WSN』 (44)
- 思想的拼图 (5)
- 开源 OpenSource (2)
- Framework 开发框架 (0)
- Software Engineering 软件工程 (2)
- IT项目管理 (6)
- Networking 网络技术 (2)
- Java (6)
- C语言 ANSI C (22)
- .NET / C# (9)
- C++ (12)
- Web 语言 Html/Xml (5)
- Groovy on Grails (1)
- Algorithm 算法 (1)
- Database 数据库技术 (5)
- Tools (21)
- VM 虚拟机 (3)
- WSN (wireless sensor network) (2)
- Linux 命令专辑 (3)
- PHP (0)
- 办公软件 (3)
最新评论
-
cfczdws:
感谢楼主,查了半天终于发现居然是htmlentities()做 ...
htmlentities()函数把中文转成了乱码 -
decoxiaohan:
这本书的名字 有谁知道????~~~
OMNeT++中文用户手册(完全版) -
huonie:
怎么下载啊
OMNeT++中文用户手册(完全版) -
huonie:
没有内容啊
OMNeT++中文用户手册(完全版) -
kyx0413:
谢谢先 先看看
OMNeT++中文用户手册(完全版)
第一篇
C语言编程中有时会遇到一些参数个数可变的函数,例如printf()函数,其函数原型为:
int printf( const char* format, ...);
它除了有一个参数format固定以外,后面跟的参数的个数和类型是可变的(用三个点“…”做参数占位符),实际调用时可以有以下的形式:
printf("%d",i);
printf("%s",s);
printf("the number is %d ,string is:%s", i, s);
一个简单的可变参数的C函数
先看例子程序。该函数至少有一个整数参数,其后占位符…,表示后面参数的个数不定。在这个例子里,所有的输入参数必须都是整数,函数的功能只是打印所有参数的值。函数代码如下:
//示例代码1:可变参数函数的使用
#include "stdio.h"
#include "stdarg.h"
void simple_va_fun(int start, ...)
{
va_list arg_ptr;
int nArgValue =start;
int nArgCout="0"; //可变参数的数目
va_start(arg_ptr,start); //以固定参数的地址为起点确定变参的内存起始地址。
do
{
++nArgCout;
printf("the %d th arg: %d",nArgCout,nArgValue); //输出各参数的值
nArgValue = va_arg(arg_ptr,int); //得到下一个可变参数的值
} while(nArgValue != -1);
return;
}
int main(int argc, char* argv[])
{
simple_va_fun(100,-1);
simple_va_fun(100,200,-1);
return 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 );
va在这里是variable-argument(可变参数)的意思。
这些宏定义在stdarg.h中,所以用到可变参数的程序应该包含这个头文件。
⑵函数里首先定义一个va_list型的变量,这里是arg_ptr,这个变量是存储参数地址的指针.因为得到参数的地址之后,再结合参数的类型,才能得到参数的值。
⑶然后用va_start宏初始化⑵中定义的变量arg_ptr,这个宏的第二个参数是可变参数列表的前一个参数,即最后一个固定参数。
⑷然后依次用va_arg宏使arg_ptr返回可变参数的地址,得到这个地址之后,结合参数的类型,就可以得到参数的值。
⑸设定结束条件,这里的条件就是判断参数值是否为-1。注意被调的函数在调用时是不知道可变参数的正确数目的,程序员必须自己在代码中指明结束条件。至于为什么它不会知道参数的数目,在看完这几个宏的内部实现机制后,自然就会明白。
第二篇
C语言之可变参数问题
C语言中有一种长度不确定的参数,形如:"…",它主要用在参数个数不确定的函数中,我们最容易想到的例子是printf函数。
原型:
int printf( const char *format [, argument]... );
使用例:
printf("Enjoy yourself everyday!\n");
printf("The value is %d!\n", value);
这种可变参数可以说是C语言一个比较难理解的部分,这里会由几个问题引发一些对它的分析。
注意:在C++中有函数重载(overload)可以用来区别不同函数参数的调用,但它还是不能表示任意数量的函数参数。
问题:printf的实现
请问,如何自己实现printf函数,如何处理其中的可变参数问题? 答案与分析:
在标准C语言中定义了一个头文件专门用来对付可变参数列表,它包含了一组宏,和一个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)))[-1]
自己实现printf:
#include
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语言编程中有时会遇到一些参数个数可变的函数,例如printf()函数,其函数原型为:
int printf( const char* format, ...);
它除了有一个参数format固定以外,后面跟的参数的个数和类型是可变的(用三个点“…”做参数占位符),实际调用时可以有以下的形式:
printf("%d",i);
printf("%s",s);
printf("the number is %d ,string is:%s", i, s);
一个简单的可变参数的C函数
先看例子程序。该函数至少有一个整数参数,其后占位符…,表示后面参数的个数不定。在这个例子里,所有的输入参数必须都是整数,函数的功能只是打印所有参数的值。函数代码如下:
//示例代码1:可变参数函数的使用
#include "stdio.h"
#include "stdarg.h"
void simple_va_fun(int start, ...)
{
va_list arg_ptr;
int nArgValue =start;
int nArgCout="0"; //可变参数的数目
va_start(arg_ptr,start); //以固定参数的地址为起点确定变参的内存起始地址。
do
{
++nArgCout;
printf("the %d th arg: %d",nArgCout,nArgValue); //输出各参数的值
nArgValue = va_arg(arg_ptr,int); //得到下一个可变参数的值
} while(nArgValue != -1);
return;
}
int main(int argc, char* argv[])
{
simple_va_fun(100,-1);
simple_va_fun(100,200,-1);
return 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 );
va在这里是variable-argument(可变参数)的意思。
这些宏定义在stdarg.h中,所以用到可变参数的程序应该包含这个头文件。
⑵函数里首先定义一个va_list型的变量,这里是arg_ptr,这个变量是存储参数地址的指针.因为得到参数的地址之后,再结合参数的类型,才能得到参数的值。
⑶然后用va_start宏初始化⑵中定义的变量arg_ptr,这个宏的第二个参数是可变参数列表的前一个参数,即最后一个固定参数。
⑷然后依次用va_arg宏使arg_ptr返回可变参数的地址,得到这个地址之后,结合参数的类型,就可以得到参数的值。
⑸设定结束条件,这里的条件就是判断参数值是否为-1。注意被调的函数在调用时是不知道可变参数的正确数目的,程序员必须自己在代码中指明结束条件。至于为什么它不会知道参数的数目,在看完这几个宏的内部实现机制后,自然就会明白。
第二篇
C语言之可变参数问题
C语言中有一种长度不确定的参数,形如:"…",它主要用在参数个数不确定的函数中,我们最容易想到的例子是printf函数。
原型:
int printf( const char *format [, argument]... );
使用例:
printf("Enjoy yourself everyday!\n");
printf("The value is %d!\n", value);
这种可变参数可以说是C语言一个比较难理解的部分,这里会由几个问题引发一些对它的分析。
注意:在C++中有函数重载(overload)可以用来区别不同函数参数的调用,但它还是不能表示任意数量的函数参数。
问题:printf的实现
请问,如何自己实现printf函数,如何处理其中的可变参数问题? 答案与分析:
在标准C语言中定义了一个头文件专门用来对付可变参数列表,它包含了一组宏,和一个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)))[-1]
自己实现printf:
#include
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()来确定所有实际调用时可变长参数的类型和值。
发表评论
-
不用库函数,自己实现strcpy和memcpy函数
2009-04-04 02:52 35271.代码实现 char* strcpy(char* strD ... -
C/C++:对指针进行操作的函数
2009-04-03 03:37 1175先看个例子 void add_array(int* a){ ... -
C语言编程常见问题解答之指针和内存分配
2009-03-30 02:51 2622指针为C语言编程提供了 ... -
详细解析C语言中的sizeof
2009-03-24 00:20 1254一、sizeof的概念 s ... -
Array vs. Malloc: A C语言问题
2009-03-16 23:57 1601code: int foo[256]; 和 int *b ... -
数组作函数的参数 和 返回值return
2009-03-16 20:40 18352同其它变量一样,数组也可以作函数的参数。数组元素只能作 ... -
C/C++:函数参数传递方式
2009-03-16 20:26 3163传递变量名,传递指针 ... -
C语言的三种整型数据类型:int、short int和long int
2009-03-15 20:58 104667int数据类型的位数为16位,short int数据类型的位数 ... -
C语言,结构体(struct) 用法
2009-03-15 19:52 5413结构(struct) 结构是由基本数据类型构成的、 ... -
C语言常量的定义方法
2009-03-14 23:47 2895常量是在程序运算过程中不变的量。 常量在程序中经常 ... -
typedef struct 和 typedef struct tagname 区别
2009-03-12 20:25 2548在struct, union, 和 enum 的定义中tag ... -
C语言中typedef用法
2009-03-12 19:42 65681. 基本解释 typedef为C语言的关键字,作用 ... -
i++和++i的区别
2009-03-12 01:14 1897如果有表达式 a = i++ 它等价于 a = i ; i ... -
c语言中的struct和union
2009-03-10 04:22 8654联 合(union) 1. 联合说明和联合变 ... -
ntoh16 与 hton16
2009-03-10 01:49 3186/* * Functions hton16 and ht ... -
return 1 或 return 0 的作用
2009-03-07 01:43 7974在C或C++中常有一些程序,结尾有不影响运行的 return ... -
GNU C 扩展之__attribute__ 机制简介
2009-03-04 04:44 1232GNU C的一大特色(却不 ... -
#ifdef and #ifndef
2009-03-01 01:53 1566Preprocessor: #ifdef and #ifnde ... -
c/c++中#include <>与#include""区别
2009-02-28 22:45 33179<>先去系统目录中找头文件,如果没有在到当前目录下 ... -
基本的字节序
2009-02-22 03:22 1121对于单一的字节(a byte),大部分处理器以相同的顺序处理位 ...
相关推荐
能够按照格式化输出字符串数据,长度不受限制,亲测十几兆都正常。 #include using namespace std;
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$> $$$$$$$$$$$$$$$$$来说$$$$$$$$$$$$$$$$$$$$$$ ...
一种windows下const char*转LPCWSTR的方法演示
exec函数族中包括6个函数: #include int execl(const char *path, const char *arg, ...); int execlp(const char *file, const char *arg, ...); int execle(const char *path, const char *arg,..., char * ...
golang调用c++DLL返回值为char*参数为const char*,读取返回DLL返回值,传递char*型参数
std::string、char*、const char*转托管byte数组或托管字符串String
对数在C99中实现的简单日志记录库用法和... 每个函数采用一个printf格式字符串,后跟其他参数: log_trace ( " Hello %s " , " world " ) 结果是将给定格式的行打印到stderr: 20:18:26 TRACE src/main.c:11: Hello
原型: int _printf(const char *, ...);一些例子整数输入: _printf("There are %i dozens in a gross\n", 12); 产出: There are 12 dozens in a gross 特点输入: _printf("The first letter in the alphabet is...
int replace_str(const char * src, const char * key_src, const char * key, char ** buf); int replace_count(const char * src, const char * key_src, int * n); int main() { char * str = "a 123 b 156 LL a...
先看代码 代码如下:printf(“hello,world!”);其参数个数为1个。...后面的三个点…表示printf参数个数是不定的.如何实现可变参数函数?2. 编写可变函数准备为了编写可变参数函数,我们通常需要用到头文
char*是从学习C语言开始就已经和我们形影不离的了,有许多API都是以char*作为参数输入的。所以熟练掌握三者之间的转换十分必要。 以下我用简单的图示指出三者之间的关系,并以标号对应转换的方法。 1 string to ...
每种语言都对正则表达式有着不同程度的支持,在C语言中,有输入功能的这三个函数对正则表达式的支持并不强大,但是我们还是有必要了解一下。 首先来看看他们的原型: #include int scanf(const char *format, ...)...
// 查找当前目录下的所有文件(不包括子目录),制定查找文件类型,如:*.txt,*.lua,*.* void FindAllFile(const char* pCurDir, const char* pFileType, vector<string>& vtFiles); // 查找当前目录下的...
int VA gzprintf (gzFile file, const char *format, ...); int gzputs (gzFile file, const char *s); char * gzgets (gzFile file, char *buf, int len); int gzputc (gzFile file, int c); int gzgetc ...
7. C中可变参数函数实现 38 8. C程序内存中组成部分 41 9. C编程拾粹 42 10. C语言中实现数组的动态增长 44 11. C语言中的位运算 46 12. 浮点数的存储格式: 50 13. 位域 58 14. C语言函数二维数组传递方法 ...
本文件是学习使用my_printf(const char *fmt, ...) 。const char *fmt 和 ... 是函数参数列表的一部分,通常用于格式化输出函数。 my_printf主要是使用myprintf处理字符串,把各种格式化的字符串处理好,放入一个...
ftpclient(const char* connmode="port", const char* transmode="binary"); ~ftpclient(void); int connect(const char* addr, short port); int disconnect(); int login(const char* username, const char*...
std::unique_ptr<const char*>p(new const char*(readfile64("{\"filename\":\"D:\\\\job\\\\greatwall\\\\test\\\\1.jpg\"}"))); if (!*p.get()) return -1; int len = strlen(*p.get()); printf("%s\n",*p.get...
C语言中 int main(int argc,char *argv[])的两个参数详解 argc是命令行总的参数个数; argv[]是argc个参数,其中第0个参数是程序的全名,以后的参数。命令行后面跟的用户输入的参数。 int main(int argc, char* ...
难道在C语言中一个结构不能包含指向自己的指针吗? . . . . 3 1.7 怎样建立和理解非常复杂的声明?例如定义一个包含N 个指向返 回指向字符的指针的函数的指针的数组? . . . . . . . . . . . . . . 3 1.8 函数只定义...