va編譯c語言,val3編程語言基礎

本文目錄一覽:

代碼「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-tw/n/303379.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-31 11:49
下一篇 2024-12-31 11:49

相關推薦

  • Python基礎代碼用法介紹

    本文將從多個方面對Python基礎代碼進行解析和詳細闡述,力求讓讀者深刻理解Python基礎代碼。通過本文的學習,相信大家對Python的學習和應用會更加輕鬆和高效。 一、變數和數…

    編程 2025-04-29
  • AES加密解密演算法的C語言實現

    AES(Advanced Encryption Standard)是一種對稱加密演算法,可用於對數據進行加密和解密。在本篇文章中,我們將介紹C語言中如何實現AES演算法,並對實現過程進…

    編程 2025-04-29
  • 學習Python對學習C語言有幫助嗎?

    Python和C語言是兩種非常受歡迎的編程語言,在程序開發中都扮演著非常重要的角色。那麼,學習Python對學習C語言有幫助嗎?答案是肯定的。在本文中,我們將從多個角度探討Pyth…

    編程 2025-04-29
  • Python被稱為膠水語言

    Python作為一種跨平台的解釋性高級語言,最大的特點是被稱為”膠水語言”。 一、簡單易學 Python的語法簡單易學,更加人性化,這使得它成為了初學者的入…

    編程 2025-04-29
  • 數據結構與演算法基礎青島大學PPT解析

    本文將從多個方面對數據結構與演算法基礎青島大學PPT進行詳細的闡述,包括數據類型、集合類型、排序演算法、字元串匹配和動態規劃等內容。通過對這些內容的解析,讀者可以更好地了解數據結構與算…

    編程 2025-04-29
  • Python零基礎PDF下載

    本文將為大家介紹如何使用Python下載PDF文件,適合初學者上手實踐。 一、安裝必要的庫 在Python中,我們需要使用urllib和requests庫來獲取PDF文件的鏈接,並…

    編程 2025-04-29
  • 樹莓派DIY無人機一:製作基礎

    本文將介紹如何使用樹莓派製作一個可飛行的小型無人機。本文將介紹樹莓派的選型、比例積木的使用、無線電通信以及如何控制飛行器的基本運動。 一、樹莓派的選型 在DIY無人機中,樹莓派是必…

    編程 2025-04-29
  • OpenJudge答案1.6的C語言實現

    本文將從多個方面詳細闡述OpenJudge答案1.6在C語言中的實現方法,幫助初學者更好地學習和理解。 一、需求概述 OpenJudge答案1.6的要求是,輸入兩個整數a和b,輸出…

    編程 2025-04-29
  • Polyphone音頻編輯器基礎入門教程

    Polyphone是一款免費的音頻編輯器,可用於編輯.sf2和.sfz格式的音色庫。本文將詳細介紹Polyphone的基礎操作及使用方法。 一、安裝和簡介 首先,我們需要下載並安裝…

    編程 2025-04-29
  • Python按位運算符和C語言

    本文將從多個方面詳細闡述Python按位運算符和C語言的相關內容,並給出相應的代碼示例。 一、概述 Python是一種動態的、面向對象的編程語言,其按位運算符是用於按位操作的運算符…

    編程 2025-04-29

發表回復

登錄後才能評論