真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

C語言中可變參數(shù)的原理是什么

C語言中可變參數(shù)的原理是什么,相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。

在臨桂等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強發(fā)展的系統(tǒng)性、市場前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供成都網(wǎng)站制作、成都做網(wǎng)站 網(wǎng)站設(shè)計制作按需策劃,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),營銷型網(wǎng)站建設(shè),外貿(mào)網(wǎng)站制作,臨桂網(wǎng)站建設(shè)費用合理。

var_list可變參數(shù)介紹

VA_LIST 是在C語言中解決變參問題的一組宏,原型:

typedef char* va_list;

其實就是個char*類型變量

除了var_list ,我們還需要幾個宏來實現(xiàn)可變參數(shù)

「va_start、va_arg、va_end」

#define _INTSIZEOF(n)   ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) ) #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )//第一個可選參數(shù)地址 #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )//下一個參數(shù)地址 #define va_end(ap)    ( ap = (va_list)0 )                  // 將指針置為無效

簡單使用可變參數(shù)

#include  #include  int AveInt(int, ...); void main() {     printf("%d\t", AveInt(2, 2, 3));     printf("%d\t", AveInt(4, 2, 4, 6, 8));     return; }  int AveInt(int v, ...) {     int ReturnValue = 0;     int i = v;     va_list ap;     va_start(ap, v);     while (i > 0)     {         ReturnValue += va_arg(ap, int);         i--;     }     va_end(ap);     return ReturnValue /= v; }

啊這..

可變參數(shù)原理

在進(jìn)程中,堆棧地址是從高到低分配的.當(dāng)執(zhí)行一個函數(shù)的時候,將參數(shù)列表入棧,壓入堆棧的高地址部分,然后入棧函數(shù)的返回地址,接著入棧函數(shù)的執(zhí)行代碼,這個入棧過程,堆棧地址不斷遞減,

「黑客就是在堆棧中修改函數(shù)返回地址,執(zhí)行自己的代碼來達(dá)到執(zhí)行自己插入的代碼段的目的」.

函數(shù)在堆棧中的分布情況是:地址從高到低,依次是:函數(shù)參數(shù)列表,函數(shù)返回地址,函數(shù)執(zhí)行代碼段.

說這么多直接上代碼演示吧..

#include  #include  int AveInt(int, ...); void main() {     printf("AveInt(2, 2, 4): %d\n", AveInt(2, 2, 4));     return; }  int AveInt(int argc, ...) {     int ReturnValue = 0;     int next = 0;     va_list arg_ptr;      va_start(arg_ptr, argc);     printf("&argc = %p\n", &argc);            //打印參數(shù)i在堆棧中的地址     printf("arg_ptr = %p\n", arg_ptr);  //打印va_start之后arg_ptr地址,比參數(shù)i的地址高sizeof(int)個字節(jié)     /*  這時arg_ptr指向下一個參數(shù)的地址 */      next = *((int*)arg_ptr);     ReturnValue += next;      next = va_arg(arg_ptr, int);     printf("arg_ptr = %p\n", arg_ptr);  //打印va_arg后arg_ptr的地址,比調(diào)用va_arg前高sizeof(int)個字節(jié)      next = *((int*)arg_ptr);     ReturnValue += next;     /*  這時arg_ptr指向下一個參數(shù)的地址 */     va_end(arg_ptr);     return ReturnValue/argc; }

輸出:

&argc = 0088FDD4 arg_ptr = 0088FDD8 arg_ptr = 0088FDDC AveInt(2, 2, 4): 3

「這個是為了介紹簡單化,所以舉的例子」

這樣有點不大方便只能獲取兩個參數(shù)的,用可變參數(shù)改變一下

#include  #include  int Arg_ave(int argc, ...); void main() {     printf("Arg_ave(2, 2, 4): %d\n", Arg_ave(2, 2, 4));     return; } int Arg_ave(int argc, ...) {     int value = 0;     int ReturnValue = 0;      va_list arg_ptr;     va_start(arg_ptr, argc);     for (int i = 0; i < argc; i++)     {         value = va_arg(arg_ptr, int);         printf("value[%d]=%d\n", i + 1, value);         ReturnValue += value;     }     return ReturnValue/argc; }

輸出

value[1]=2 value[2]=4 Arg_ave(2, 2, 4): 3

當(dāng)你理解之后你就會說就這?這么簡單,指定第一個參數(shù)是后面參數(shù)的總數(shù)就可以了,這還不隨隨便玩

別著急,精彩的來了,「可變參數(shù)的應(yīng)用」

可變參數(shù)應(yīng)用:實現(xiàn)log打印

#include  #include  #include  /*定義一個回調(diào)函數(shù)指針*/ typedef void (*libvlcFormattedLogCallback)(void* data, int level, const void* ctx, const char* message); enum libvlc_log_level {      LIBVLC_DEBUG = 0,       //調(diào)試     LIBVLC_NOTICE = 2,      //普通     LIBVLC_WARNING = 3,     //警告     LIBVLC_ERROR = 4 }      //錯誤 ; /*定義一個回調(diào)函數(shù)結(jié)構(gòu)體*/ typedef struct CallbackData {     void* managedData;     libvlcFormattedLogCallback managedCallback;     int minLogLevel;        //log 級別 } CallbackData;  /*構(gòu)造回調(diào)函數(shù)結(jié)構(gòu)體*/ void* makeCallbackData(libvlcFormattedLogCallback callback, void* data, int minLevel) {     CallbackData* result = (CallbackData *)malloc(sizeof(CallbackData));     result->managedCallback = callback;     result->managedData = data;     result->minLogLevel = minLevel;     return result; }  /*回調(diào)函數(shù)*/ void formattedLogCallback(void* data, int level, const void* ctx, const char* message) {     printf("level:%d", level);     if (level == LIBVLC_ERROR)     {         printf("LIBVLC_ERROR:%s", message);         return;     }     if (level >= LIBVLC_WARNING) {         printf("LIBVLC_WARNING:%s", message);         return;     }     if (level >= LIBVLC_NOTICE)     {         printf("LIBVLC_ERROR:%s", message);         return;     }     if (level >= LIBVLC_DEBUG) {         printf("LIBVLC_WARNING:%s", message);         return;     }           }  /*和石化log信息并執(zhí)行回調(diào)函數(shù)*/ void InteropCallback(void* data, int level, const void* ctx, const char* fmt, va_list args) {     CallbackData* callbackData = (CallbackData*)data;     if (level >= callbackData->minLogLevel)     {         va_list argsCopy;         int length = 0;          va_copy(argsCopy, args);         length = vsnprintf(NULL, 0, fmt, argsCopy);         va_end(argsCopy);          char* str = malloc(length + 1);         if (str != NULL)         {             va_copy(argsCopy, args);             vsprintf(str, fmt, argsCopy);             va_end(argsCopy);         }         else         {             // Failed to allocate log message, drop it.             return;         }         callbackData->managedCallback(callbackData->managedData, level, ctx, str);         free(str);     } } void sendLog(void* data, int level, const void* ctx, const char* fmt, ...) {     va_list va;     va_start(va, fmt);     InteropCallback(data, level, ctx, fmt, va);     va_end(va); } int main(int argc, char** argv) {     /*注冊一個回調(diào)函數(shù)結(jié)構(gòu)體,level等級為LIBVLC_WARNING 只要發(fā)送的log等級大于等于LIBVLC_WARNING次啊會觸發(fā)回調(diào)函數(shù)*/     void* callbackData = makeCallbackData(formattedLogCallback, "context", LIBVLC_WARNING);     /*發(fā)送四個等級的消息*/     sendLog(callbackData, LIBVLC_DEBUG, NULL, "This should not be displayed : %s\n","debug");     sendLog(callbackData, LIBVLC_NOTICE, NULL, "This should not be displayed : %s\n", "notick");     sendLog(callbackData, LIBVLC_WARNING, NULL, "This message level is : %s\n", "warning");     sendLog(callbackData, LIBVLC_ERROR, NULL, "Hello, %s ! You should see %ld message here : %s\n", "World", 1, "warning message");      free(callbackData);     return 0; }

輸出                                                                                                                                                                                                               

level:3LIBVLC_WARNING:This message level is : warning level:4LIBVLC_ERROR:Hello, World ! You should see 1 message here : warning message

這個使用示例精妙之處在于注冊一個指定level的回調(diào)函數(shù)makeCallbackData(formattedLogCallback, "context",  LIBVLC_WARNING);

看完上述內(nèi)容,你們掌握C語言中可變參數(shù)的原理是什么的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!


本文標(biāo)題:C語言中可變參數(shù)的原理是什么
分享路徑:http://weahome.cn/article/gpepji.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部