重庆分公司,新征程启航

为企业提供网站建设、域名注册、服务器等服务

c语言变参函数视频教程 c语言函数做形参

c语言如何定义一个可变参数函数 如何调用其输入的参数 分别

有专门的宏,处理可变参

我们提供的服务有:成都做网站、网站设计、微信公众号开发、网站优化、网站认证、越城ssl等。为上千多家企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的越城网站制作公司

void va_start( va_list arg_ptr, prev_param );

type va_arg( va_list arg_ptr, type );

void va_end( va_list arg_ptr );

一个简单的例子

void simple_va_fun(int i, ...)

{

va_list arg_ptr;

int j=0;

va_start(arg_ptr, i);

j=va_arg(arg_ptr, int);

va_end(arg_ptr);

printf("i=%d j=%d\bn", i, j);

return;

}

int main()

{

simple_va_fun(1);

simple_va_fun(1,2);

simple_va_fun(1,200);

return 0;

}

变参(C语言)

这是一个变参函数声明。

加三个点就是了。

取得参数的套路是

这样三步,就将 各个参数,放在了 buf 中。

完整函数如下:

调用如下:

其中,vsprintf 可能造成内存泄漏,因为传入的 buf 的大小未知。

可换成

函数原型:

vsprintf 函数

vsnprintf 函数

C语言变参函数Printf实现机制是什么?

在C/C++中,对函数参数的扫描是从后向前的。C/C++的函数参数是通过压入堆栈的方式来给函数传参数的(堆栈是一种先进后出的数据结构),最先压入的参数最后出来,在计算机的内存中,数据有2块,一块是堆,一块是栈(函数参数及局部变量在这里),而栈是从内存的高地址向低地址生长的,控制生长的就是堆栈指针了,最先压入的参数是在最上面,就是说在所有参数的最后面,最后压入的参数在最下面,结构上看起来是第一个,所以最后压入的参数总是能够被函数找到,因为它就在堆栈指针的上方。printf的第一个被找到的参数就是那个字符指针,就是被双引号括起来的那一部分,函数通过判断字符串里控制参数的个数来判断参数个数及数据类型,通过这些就可算出数据需要的堆栈指针的偏移量了,下面给出printf("%d,%d",a,b);(其中a、b都是int型的)的汇编代码.

.section

.data

string out = "%d,%d"

push b //最后的先压入栈中

push a //最先的后压入栈中

push $out//参数控制的那个字符串常量是最后被压入的

call printf

你会看到,参数是最后的先压入栈中,最先的后压入栈中,参数控制的那个字符串常量是最后被压入的,所以这个常量总是能被找到的。

通常情况下函数可变参数表的长度是已知的,通过num参数传入,这种函数比较容易实现。

在哪儿能找到C语言的视频教程

边用边学C语言视频教程- 专辑- 视频

边用边学C语言视频教程--第一讲 34:08; 播放: 316088 边用边学C语言视频教程--第二讲 42:55; 播放: 146905 边用边学C语言视频教程--第三讲 33:49; 播放: 79889

全国计算机等级考试二级(C语言)视频教程- 视频中心·易学院

全国计算机等级考试二级(C语言)视频教程 C语言等级考试一直是广大朋友比较头痛的,c语言视频教程针对此种情况21互联特聘请了资深的老师,录制了C语言等级考试课程,使广大朋友

C语言程序设计入门视频教程_编程开发_||电脑

2008年10月18日 C语言程序设计入门视频教程主要包括:C语言概述;数据类型,运算符和表达式;顺序程序设计和选择结构程序设计;循环控制;函数。

C语言程序设计视频教程-eNet络学院

C语言程序设计视频教程 C语言程序设计作为大学理工课大一下学期必修的课程,c语言视频教程也是本站(21shipin)所有其它编程语言的必学入门课程,学习该课程并不是要求大家能用C设计

c语言视频教程

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的描述就是这些了,我们要注意的 是不同的操作系统和硬件平台的定义有些不同,但原理却是相似的.


文章名称:c语言变参函数视频教程 c语言函数做形参
本文URL:http://cqcxhl.cn/article/dosoocp.html

其他资讯

在线咨询
服务热线
服务热线:028-86922220
TOP