易截截图软件、单文件、免安装、纯绿色、仅160KB

c/c++支持可变参数的函数

c/c++支持可变参数的函数,即函数的参数是不确定的。
一、为什么要使用可变参数的函数?
一般我们编程的时候,函数中形式参数的数目通常是确定的,在调用时要依次给出与形式参数对应的所有实际参数。但在某些情况下希望函数的参数个数可以根据需要确定,因此c语言引入可变参数函数。这也是c功能强大的一个方面,其它某些语言,比如fortran就没有这个功能。
典型的可变参数函数的例子有大家熟悉的printf()、scanf()等。
二、c/c++如何实现可变参数的函数?
为了支持可变参数函数,C语言引入新的调用协议, 即C语言调用约定 __cdecl 。 采用C/C++语言编程的时候,默认使用这个调用约定。如果要采用其它调用约定,必须添加其它关键字声明,例如WIN32 API使用PASCAL调用约定,函数名字之前必须加__stdcall关键字。
采用C调用约定时,函数的参数是从右到左入栈,个数可变。由于函数体不能预先知道传进来的参数个数,因此采用本约定时必须由函数调用者负责堆栈清理。举个例子:
//C调用约定函数
int __cdecl Add(int a, int b)
{
return (a + b);
}
函数调用:
Add(1, 2);
//汇编代码是:
push 2 ;参数b入栈
push 1 ;参数a入栈
call @Add ;调用函数。其实还有编译器用于定位函数的表达式这里把它省略了
add esp,8 ;调用者负责清栈
如果调用函数的时候使用的调用协议和函数原型中声明的不一致,就会导致栈错误,这是另外一个话题,这里不再细说。
另外c/c++编译器采用宏的形式支持可变参数函数。这些宏包括va_start、va_arg和va_end等。之所以这么做,是为了增加程序的可移植性。屏蔽不同的硬件平台造成的差异。
支持可变参数函数的所有宏都定义在stdarg.h 和 varargs.h中。例如标准ANSI形式下,这些宏的定义是:
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 )
使用宏_INTSIZEOF是为了按照整数字节对齐指针,因为c调用协议下面,参数入栈都是整数字节(指针或者值)。
三、如何定义这类的函数。
可变参数函数在不同的系统下,采用不同的形式定义。
1、用ANSI标准形式时,参数个数可变的函数的原型声明是:
type funcname(type para1, type para2, …);


相关文档:

c/c++ 内存对齐 sizeof

   一篇讲对齐比较好的文章,转贴如下:
大致标注一二:
1.内存对齐:计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地址的值是某个数k(通常它为4或8)的倍数k则被称为该数据类型的对齐模数(alignment modulus)
2.不同编译器默认的最大对齐字节数是不一样的,比如vc==8,gcc==4,可以通� ......

c/C++编译的程序占用的内存情况 文字常量区

首先看下下面这段:
int main()
{
char *name = "fengkewei";
char name1[] = "fengkewei";
char *name2 = "fengkewei";
char *name3 = "woaifengkewei";
int i = 10;
int j = 10;
int k = 11;
return 0;
}
若您觉得它们应该都保存在内存中的一块地方,那请往下看。。。。
下面是编译器为各个变量分配的内存地 ......

linux下命令行下编译c程序

-------------------------------------------
Linuxmine收集整理  作者:linux宝库 (http://www.linuxmine.com)  时间:2006-10-11
-------------------------------------------
C 是所有版本的UNIX上的系统语言.
C 在过去 ......

浅谈C/C++内存泄漏及其检测工具

BoundsChecker采用一种被称为 Code Injection的技术,来截获对分配内存和释放内存的函数的调用。简单地说,当你的程序开始运行时,BoundsChecker的DLL被自动载入进程的地址空间(这可以通过system-level的Hook实现),然后它会修改进程中对内存分配和释放的函数调用,让这些调用首先转入它的代码,然后再执行原来的代码。Bo ......

JAVA操作XML的完整例子——W3C DOM篇

这是一个用JAVA W3C DOM 进行XML操作的例子,包含了查询、增加、修改、删除、保存的基本操作。较完整的描述了一个XML的整个操作流程。适合刚入门JAVA XML操作的朋友参考和学习。
假设有XML文件:test1.xml
<?xml version="1.0" encoding="UTF-8"?>
<books>
 <book>
  <name>哈里波� ......
© 2009 ej38.com All Rights Reserved. 关于E健网联系我们 | 站点地图 | 赣ICP备09004571号