日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

stdarg.h的库函数用法小结

發(fā)布時間:2025/4/16 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 stdarg.h的库函数用法小结 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
stdarg.h的庫函數(shù) Notice that va_arg cannot determine the actual type of the argument passed to the function, but uses whatever type is passed as the type macro argument as its type.

Notice also that va_arg does not determine either whether the retrieved argument is the last argument passed to the function (or even if it is an element past the end of that list). The function should be designed in such a way that the amount of parameters can be inferred in some way by the values of either the named parameters or the additional arguments already read.

 

#include <iostream.h>

#include <stdarg.h>

?

#define? N 5

?

void print(int x,...)

{

????va_list arg;

????int i;

????int??a[N];

?

????va_start(arg,x);

????a[0]=a1;

????for(i=1;i< N;i++)

???????a[i]=va_arg(arg,int);

????va_end(arg);

????for(i=0;i< N;i++)

???????cout<<a[i]<<endl;

}

?

void main()

{

????print(6,12,24,36,48);

}

?

?

C語言中的printf函數(shù)的參數(shù)就是可變參數(shù)。

?

printf() 函數(shù)的定義如下:
int printf( const char* format, ...);
它除了一個參數(shù)format固定參數(shù)外,其他的參數(shù)都是可變的。我們可以有以下不同的調(diào)用方法:
printf("%d",i);
printf("%s",s);
printf("the number is %d ,string is:%s", i, s);
如何編寫帶有可變參數(shù)的C函數(shù)以及這些可變參數(shù)的函數(shù)編譯器是如何實
現(xiàn)的呢?

本文就這個問題進行一些探討,希望能對大家有些幫助.
(一)寫一個簡單的可變參數(shù)的C函數(shù)

下面我們來探討如何寫一個簡單的可變參數(shù)的C函數(shù).寫可變參數(shù)的
C函數(shù)要在程序中用到以下這些宏:
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(可變參數(shù))的縮寫.
這些宏定義在stdarg.h中,所以用到可變參數(shù)的程序應該包含這個
頭文件.

下面我們寫一個簡單的可變參數(shù)的函數(shù),改函數(shù)至少有一個整數(shù)
參數(shù),第二個參數(shù)也是整數(shù),是可選的.函數(shù)只是打印這兩個參數(shù)的值.
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("%d %d/n", i, j);
return;
}
我們可以在我們的頭文件中這樣聲明我們的函數(shù):
extern void simple_va_fun(int i, ...);
我們在程序中可以這樣調(diào)用:
simple_va_fun(100);
simple_va_fun(100,200);

?

以下轉(zhuǎn)自:博客

http://baike.baidu.com/view/3373010.htm?fr=ala0_1

http://blog.163.com/zhoucl_0220/blog/static/145454692009105104356573/

http://blog.csdn.net/crcr

http://hi.baidu.com/sjh9/blog/item/4f5d6fdf1696aa1048540344.html
從這個函數(shù)的實現(xiàn)可以看到,我們使用可變參數(shù)應該有以下步驟:
1)首先在函數(shù)里定義一個va_list型的變量,這里是arg_ptr,這個變
量是指向參數(shù)的指針.
2)然后用va_start宏初始化變量arg_ptr,這個宏的第二個參數(shù)是第
一個可變參數(shù)的前一個參數(shù),是一個固定的參數(shù).
3)然后用va_arg返回可變的參數(shù),并賦值給整數(shù)j. va_arg的第二個
參數(shù)是你要返回的參數(shù)的類型,這里是int型.
4)最后用va_end宏結束可變參數(shù)的獲取.然后你就可以在函數(shù)里使
用第二個參數(shù)了.如果函數(shù)有多個可變參數(shù)的,依次調(diào)用va_arg獲
取各個參數(shù).
如果我們用下面三種方法調(diào)用的話,都是合法的,但結果卻不一樣:
1)simple_va_fun(100);
結果是:100 -123456789(會變的值)
2)simple_va_fun(100,200);
結果是:100 200
3)simple_va_fun(100,200,300);
結果是:100 200
我們看到第一種調(diào)用有錯誤,第二種調(diào)用正確,第三種調(diào)用盡管結果
正確,但和我們函數(shù)最初的設計有沖突.下面一節(jié)我們探討出現(xiàn)這些結果
的原因和可變參數(shù)在編譯器中是如何處理的.

(二)可變參數(shù)在編譯器中的處理

我們知道va_start,va_arg,va_end是在stdarg.h中被定義成宏的,
由于1)硬件平臺的不同 2)編譯器的不同,所以定義的宏也有所不同,下
面以VC++中stdarg.h里x86平臺的宏定義摘錄如下(’/’號表示折行):

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(n)主要是為了某些需要內(nèi)存的對齊的系統(tǒng).C語言的函
數(shù)是從右向左壓入堆棧的,圖(1)是函數(shù)的參數(shù)在堆棧中的分布位置.我
們看到va_list被定義成char*,有一些平臺或操作系統(tǒng)定義為void*.再
看va_start的定義,定義為&v+_INTSIZEOF(v),而&v是固定參數(shù)在堆棧的
地址,所以我們運行va_start(ap, v)以后,ap指向第一個可變參數(shù)在堆
棧的地址,如圖:

高地址|-----------------------------|
|函數(shù)返回地址 |
|-----------------------------|
|....... |
|-----------------------------|
|第n個參數(shù)(第一個可變參數(shù)) |
|-----------------------------|<--va_start后ap指向
|第n-1個參數(shù)(最后一個固定參數(shù))|
低地址|-----------------------------|<-- &v
圖( 1 )

然后,我們用va_arg()取得類型t的可變參數(shù)值,以上例為int型為例,我
們看一下va_arg取int型的返回值:
j= ( *(int*)((ap += _INTSIZEOF(int))-_INTSIZEOF(int)) );
首先ap+=sizeof(int),已經(jīng)指向下一個參數(shù)的地址了.然后返回
ap-sizeof(int)的int*指針,這正是第一個可變參數(shù)在堆棧里的地址
(圖2).然后用*取得這個地址的內(nèi)容(參數(shù)值)賦給j.

高地址|-----------------------------|
|函數(shù)返回地址 |
|-----------------------------|
|....... |
|-----------------------------|<--va_arg后ap指向
|第n個參數(shù)(第一個可變參數(shù)) |
|-----------------------------|<--va_start后ap指向
|第n-1個參數(shù)(最后一個固定參數(shù))|
低地址|-----------------------------|<-- &v
圖( 2 )

最后要說的是va_end宏的意思,x86平臺定義為ap=(char*)0;使ap不再
指向堆棧,而是跟NULL一樣.有些直接定義為((void*)0),這樣編譯器不
會為va_end產(chǎn)生代碼,例如gcc在linux的x86平臺就是這樣定義的.
在這里大家要注意一個問題:由于參數(shù)的地址用于va_start宏,所
以參數(shù)不能聲明為寄存器變量或作為函數(shù)或數(shù)組類型.
關于va_start, va_arg, va_end的描述就是這些了,我們要注意的
是不同的操作系統(tǒng)和硬件平臺的定義有些不同,但原理卻是相似的.

(三)可變參數(shù)在編程中要注意的問題

因為va_start, va_arg, va_end等定義成宏,所以它顯得很愚蠢,
可變參數(shù)的類型和個數(shù)完全在該函數(shù)中由程序代碼控制,它并不能智能
地識別不同參數(shù)的個數(shù)和類型.
有人會問:那么printf中不是實現(xiàn)了智能識別參數(shù)嗎?那是因為函數(shù)
printf是從固定參數(shù)format字符串來分析出參數(shù)的類型,再調(diào)用va_arg
的來獲取可變參數(shù)的.也就是說,你想實現(xiàn)智能識別可變參數(shù)的話是要通
過在自己的程序里作判斷來實現(xiàn)的.
另外有一個問題,因為編譯器對可變參數(shù)的函數(shù)的原型檢查不夠嚴
格,對編程查錯不利.如果simple_va_fun()改為:
void simple_va_fun(int i, ...)
{
va_list arg_ptr;
char *s=NULL;

va_start(arg_ptr, i);
s=va_arg(arg_ptr, char*);
va_end(arg_ptr);
printf("%d %s/n", i, s);
return;
}
可變參數(shù)為char*型,當我們忘記用兩個參數(shù)來調(diào)用該函數(shù)時,就會出現(xiàn)
core dump(Unix) 或者頁面非法的錯誤(window平臺).但也有可能不出
錯,但錯誤卻是難以發(fā)現(xiàn),不利于我們寫出高質(zhì)量的程序.
以下提一下va系列宏的兼容性.
System V Unix把va_start定義為只有一個參數(shù)的宏:
va_start(va_list arg_ptr);
而ANSI C則定義為:
va_start(va_list arg_ptr, prev_param);
如果我們要用system V的定義,應該用vararg.h頭文件中所定義的
宏,ANSI C的宏跟system V的宏是不兼容的,我們一般都用ANSI C,所以
用ANSI C的定義就夠了,也便于程序的移植.


小結:
可變參數(shù)的函數(shù)原理其實很簡單,而va系列是以宏定義來定義的,實
現(xiàn)跟堆棧相關.我們寫一個可變函數(shù)的C函數(shù)時,有利也有弊,所以在不必
要的場合,我們無需用到可變參數(shù).如果在C++里,我們應該利用C++的多
態(tài)性來實現(xiàn)可變參數(shù)的功能,盡量避免用C語言的方式來實現(xiàn).??

總結

以上是生活随笔為你收集整理的stdarg.h的库函数用法小结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。