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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

具体解释可变參数列表

發布時間:2023/11/27 生活经验 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 具体解释可变參数列表 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
可變參數 ? 至少有一個參數 比如:void add(int a,… ){}
例題? 模擬printf()函數


#include?<stdio.h>

#include?<stdarg.h>

void?myprintf(constchar?*format, ...)

{

? ??va_list?ap;

? ??char?c;

? ??va_start(ap, format);

? ??while?((c = *format++))

? ? {

? ? ? ??switch(c)

? ? ? ? {

? ? ? ? ? ??case?'c':

? ? ? ? ? ? {

? ? ? ? ? ? ? ??char?ch =?va_arg(ap,?int);

? ? ? ? ? ? ? ??putchar(ch);

? ? ? ? ? ? ? ??break;

? ? ? ? ? ? }

? ? ? ? ? ??case?'s':

? ? ? ? ? ? {

? ? ? ? ? ? ? ??char?*p =?va_arg(ap,?char?*);

? ? ? ? ? ? ? ??fputs(p,?stdout);

? ? ? ? ? ? ? ??break;

? ? ? ? ? ? }

? ? ? ? ? ??default:

? ? ? ? ? ? ? ??putchar(c);

? ? ? ? ? ? ? ??break;

? ? ? ? }

? ? }

? ??va_end(ap);

}


int?main(void)

{

? ??myprintf("s ccc\n","hello",'b','i','t');

? ??return?0;

}




須要調用到 stdarg.h 標準庫的 va_list 類型和va_start、va_arg、va_end宏 va在這里的意思是variable argument(可變參數)
//va_list 首先在函數里定義一個va_list型的變量,這個變量時指向參數的指針,為訪問可變參數列表中的參數,它必須聲明一個對象 比如:va_list?ap; //va_start(,) 用va_start宏初始化定義剛聲明的對象,初始化結果供va_arg宏和va_end宏使用 比如:va_start(ap, format); //va_arg ?然后用VA_ARG返回可變的參數,VA_ARG的第二個參數是你要返回的參數的類型。每使用一次va_arg,va_list所聲明的變量指針往后移一個(假設函數有多個可變參數的,依次調用VA_ARG獲取各個參數)。 ? ? ?比如:char?ch =?va_arg(ap,?int); //va_end?最后用va_end宏結束可變參數的獲取.然后你就能夠在函數里使?用第二個參數了.假設函數有多個可變參數的,依次調用va_arg獲?取各個參數.?



可變參數在編譯器中的處理?
我們知道va_start,va_arg,va_end是在stdarg.h中被定義成宏的, 因為硬件平臺的不同或編譯器的不同,所以定義的宏也有所不同,以下是VC++6.0中stdarg.h里的代碼
???? 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)主要是為了某些須要內存的對齊的系統.這個宏的目的是為了將n的長度化為int長度的整數倍。
比如:n為5,二進制就是101b。int長度為4,二進制為100b。那么n化為int長度的整數倍就應該為8。

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的描寫敘述就是這些了,我們要注意的 是不同的操作系統和硬件平臺的定義有些不同,但原理卻是相似的.?










轉載于:https://www.cnblogs.com/blfbuaa/p/7404062.html

總結

以上是生活随笔為你收集整理的具体解释可变參数列表的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。