本文目錄一覽:
- 1、代碼“va_start(ap,fmt)”是什麼意思?
- 2、用VA2019學C語言,出現問題:返回值被忽略:“scanf”。那個sdl檢測在哪關?
- 3、C語言的變參技術,va_start,va_arg,va_end這幾個函數怎麼用?
- 4、在vasual c++中編譯switch語句出現的問題(C程序)
- 5、c語言va_arg使用
- 6、VS2008 C語言 編譯與運行
代碼“va_start(ap,fmt)”是什麼意思?
VA_LIST 是在C語言中解決變參問題的一組宏,在stdarg.h頭文件下。
VA_LIST的用法:
首先在函數里定義一具VA_LIST型的變量,這個變量是指向參數的指針,然後用VA_START宏初始化變量剛定義的VA_LIST變量,這個宏的第二個參數是第一個可變參數的前一個參數,是一個固定的參數。
然後用VA_ARG返回可變的參數,VA_ARG的第二個參數是你要返回的參數的類型。最後用VA_END宏結束可變參數的獲取。然後你就可以在函數里使用第二個參數了。如果函數有多個可變參數的,依次調用VA_ARG獲取各個參數。
VA_LIST在編譯器中的處理:
在運行VA_START(ap,v)以後,ap指向第一個可變參數在堆棧的地址。VA_ARG()取得類型t的可變參數值,在這步操作中首先apt = sizeof(t類型),讓ap指向下一個參數的地址。然後返回ap-sizeof(t類型)的t類型*指針,這正是 第一個可變參數在堆棧里的地址。然後用*取得這個地址的內容。
VA_END(),X86平台定義為ap = ((char*)0),使ap不再指向堆棧,而是跟NULL一樣,有些直接定義為((void*)0),這樣編譯器不會為VA_END產生代碼,例如gcc在Linux的X86平台就是這樣定義的。
要注意的是:由於參數的地址用於VA_START宏,所以參數不能聲明為寄存器變量,或作為函數或數組類型。
用VA2019學C語言,出現問題:返回值被忽略:“scanf”。那個sdl檢測在哪關?
這個與SDL無關的,你加個if就可以了
if
(scanf(“%d”,a);
//後面直接用分號
SDL在項目屬性中
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的描述就是這些了,我們要注意的 是不同的操作系統和硬件平台的定義有些不同,但原理卻是相似的.
在vasual c++中編譯switch語句出現的問題(C程序)
int main(void)
{
char answer = 0;/* Stores an input character */
printf(“Enter Y or N:”);
scanf_s(“%c”, answer);
switch (answer)
{
case ‘y’:
printf(“\nYou responded in the affirmetive.”);
break; //你小寫y這裡沒寫語句
case ‘Y’:
printf(“\nYou responded in the affirmetive.”);
break;
case ‘n’:
case ‘N’:
printf(“\nYou responded in the negative.”);
break;
default: printf(“\nYou did not respond correctly…”);
break;
} return 0;
c語言va_arg使用
va_arg是一個宏定義,用於處理函數不確定參數個數時,即可變參數列表時對參數的取用。
1 頭文件:
#include stdarg.h
2 形式:
type va_arg(va_list ap, type);
3 說明:
這個宏被展開成一個包含類型為type,值為ap的表達式。參數ap應該首先被宏va_start 或 va_copy初始化,但又必須在被宏va_end調用之前使用。每次調用va_arg都會改變ap值使得後續的參數值能被依次添加。參數type應該是一個類型名,並且用type*能夠得到該類型的指針類型。如果type為空,或者type和實際參數不匹配, 那麼除了以下兩種情況,這個宏的行為是未定義的。
1) 一個是帶符號整型,另一個是與之對應的無符號整型,並且值可以被表達成這兩種類型的任何一種;
2) 一個是空類型指針,另一個是字符類型指針。
第一次調用va_arg返回parmN之後的參數值,後續的調用依次返回剩下的參數值。parmN應為函數中“…”前最後一個參數值。
VS2008 C語言 編譯與運行
使用VS2008創建C語言/C++工程,並編譯運行調試,步驟如下:
1.打開VS2008
2.打開了VS2008的主界面,然後選擇,文件→新建→項目
彈出如圖對話框
3、在項目類型中選擇VC++→win32 然後在右側模板中選擇win32控制台應用程序,再在下面輸入一個名稱(項目名稱,不用帶.C)選擇保存位置後確定好了,彈出個對話框,不管它,下一步
4、接下來注意了,這個對話框中,應用程序類型要選擇控制台應用程序,附加選項一定要選中“空項目”。然後點完成。
5、在源文件上點右鍵,選擇“添加→新建項”。這裡注意,如果你已經有寫好的C源文件,那麼要選擇“現有項”又打開個對話框
6、輸入如下示例代碼
這樣工程就創建OK了,
調試快捷鍵是 F5
直接運行快捷鍵是 CTRL + F5
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/303379.html