成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

C語言可變參數(shù)的原理和應(yīng)用

開發(fā) 后端
C語言中沒有函數(shù)重載,解決不定數(shù)目函數(shù)參數(shù)問題變得比較麻煩;即使采用C++,如果參數(shù)個(gè)數(shù)不能確定,也很難采用函數(shù)重載.對(duì)這種情況,有些人采用指針參數(shù)來解決問題。

 [[373935]]

本文轉(zhuǎn)載自微信公眾號(hào)「編程學(xué)習(xí)基地  」,作者deroy  。轉(zhuǎn)載本文請(qǐng)聯(lián)系編程學(xué)習(xí)基地  公眾號(hào)。 

概述

C語言中沒有函數(shù)重載,解決不定數(shù)目函數(shù)參數(shù)問題變得比較麻煩;

即使采用C++,如果參數(shù)個(gè)數(shù)不能確定,也很難采用函數(shù)重載.對(duì)這種情況,有些人采用指針參數(shù)來解決問題

var_list可變參數(shù)介紹

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

  1. typedef char* va_list; 

其實(shí)就是個(gè)char*類型變量

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

「va_start、va_arg、va_end」

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

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

  1. #include <stdio.h> 
  2. #include <stdarg.h> 
  3. int AveInt(int, ...); 
  4. void main() 
  5.     printf("%d\t", AveInt(2, 2, 3)); 
  6.     printf("%d\t", AveInt(4, 2, 4, 6, 8)); 
  7.     return
  8.  
  9. int AveInt(int v, ...) 
  10.     int ReturnValue = 0; 
  11.     int i = v; 
  12.     va_list ap; 
  13.     va_start(ap, v); 
  14.     while (i > 0) 
  15.     { 
  16.         ReturnValue += va_arg(ap, int); 
  17.         i--; 
  18.     } 
  19.     va_end(ap); 
  20.     return ReturnValue /= v; 

啊這..

可變參數(shù)原理

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

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

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

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

  1. #include <stdio.h> 
  2. #include <stdarg.h> 
  3. int AveInt(int, ...); 
  4. void main() 
  5.     printf("AveInt(2, 2, 4): %d\n", AveInt(2, 2, 4)); 
  6.     return
  7.  
  8. int AveInt(int argc, ...) 
  9.     int ReturnValue = 0; 
  10.     int next = 0; 
  11.     va_list arg_ptr; 
  12.  
  13.     va_start(arg_ptr, argc); 
  14.     printf("&argc = %p\n", &argc);            //打印參數(shù)i在堆棧中的地址 
  15.     printf("arg_ptr = %p\n", arg_ptr);  //打印va_start之后arg_ptr地址,比參數(shù)i的地址高sizeof(int)個(gè)字節(jié) 
  16.     /*  這時(shí)arg_ptr指向下一個(gè)參數(shù)的地址 */ 
  17.  
  18.     next = *((int*)arg_ptr); 
  19.     ReturnValue += next
  20.  
  21.     next = va_arg(arg_ptr, int); 
  22.     printf("arg_ptr = %p\n", arg_ptr);  //打印va_arg后arg_ptr的地址,比調(diào)用va_arg前高sizeof(int)個(gè)字節(jié) 
  23.  
  24.     next = *((int*)arg_ptr); 
  25.     ReturnValue += next
  26.     /*  這時(shí)arg_ptr指向下一個(gè)參數(shù)的地址 */ 
  27.     va_end(arg_ptr); 
  28.     return ReturnValue/argc; 

輸出:

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

「這個(gè)是為了介紹簡(jiǎn)單化,所以舉的例子」

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

  1. #include <stdio.h> 
  2. #include <stdarg.h> 
  3. int Arg_ave(int argc, ...); 
  4. void main() 
  5.     printf("Arg_ave(2, 2, 4): %d\n", Arg_ave(2, 2, 4)); 
  6.     return
  7. int Arg_ave(int argc, ...) 
  8.     int value = 0; 
  9.     int ReturnValue = 0; 
  10.  
  11.     va_list arg_ptr; 
  12.     va_start(arg_ptr, argc); 
  13.     for (int i = 0; i < argc; i++) 
  14.     { 
  15.         value = va_arg(arg_ptr, int); 
  16.         printf("value[%d]=%d\n", i + 1, value); 
  17.         ReturnValue += value; 
  18.     } 
  19.     return ReturnValue/argc; 

輸出

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

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

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

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

  1. #include <stdarg.h> 
  2. #include <stdio.h> 
  3. #include <stdlib.h> 
  4. /*定義一個(gè)回調(diào)函數(shù)指針*/ 
  5. typedef void (*libvlcFormattedLogCallback)(void* data, int level, const void* ctx, const char* message); 
  6. enum libvlc_log_level {  
  7.     LIBVLC_DEBUG = 0,       //調(diào)試 
  8.     LIBVLC_NOTICE = 2,      //普通 
  9.     LIBVLC_WARNING = 3,     //警告 
  10.     LIBVLC_ERROR = 4 }      //錯(cuò)誤 
  11. /*定義一個(gè)回調(diào)函數(shù)結(jié)構(gòu)體*/ 
  12. typedef struct CallbackData { 
  13.     void* managedData; 
  14.     libvlcFormattedLogCallback managedCallback; 
  15.     int minLogLevel;        //log 級(jí)別 
  16. } CallbackData; 
  17.  
  18. /*構(gòu)造回調(diào)函數(shù)結(jié)構(gòu)體*/ 
  19. void* makeCallbackData(libvlcFormattedLogCallback callback, void* data, int minLevel) 
  20.     CallbackData* result = (CallbackData *)malloc(sizeof(CallbackData)); 
  21.     result->managedCallback = callback; 
  22.     result->managedData = data; 
  23.     result->minLogLevel = minLevel; 
  24.     return result; 
  25.  
  26. /*回調(diào)函數(shù)*/ 
  27. void formattedLogCallback(void* data, int level, const void* ctx, const char* message) 
  28.     printf("level:%d"level); 
  29.     if (level == LIBVLC_ERROR) 
  30.     { 
  31.         printf("LIBVLC_ERROR:%s", message); 
  32.         return
  33.     } 
  34.     if (level >= LIBVLC_WARNING) { 
  35.         printf("LIBVLC_WARNING:%s", message); 
  36.         return
  37.     } 
  38.     if (level >= LIBVLC_NOTICE) 
  39.     { 
  40.         printf("LIBVLC_ERROR:%s", message); 
  41.         return
  42.     } 
  43.     if (level >= LIBVLC_DEBUG) { 
  44.         printf("LIBVLC_WARNING:%s", message); 
  45.         return
  46.     } 
  47.      
  48.      
  49.  
  50. /*和石化log信息并執(zhí)行回調(diào)函數(shù)*/ 
  51. void InteropCallback(void* data, int level, const void* ctx, const char* fmt, va_list args) 
  52.     CallbackData* callbackData = (CallbackData*)data; 
  53.     if (level >= callbackData->minLogLevel) 
  54.     { 
  55.         va_list argsCopy; 
  56.         int length = 0; 
  57.  
  58.         va_copy(argsCopy, args); 
  59.         length = vsnprintf(NULL, 0, fmt, argsCopy); 
  60.         va_end(argsCopy); 
  61.  
  62.         char* str = malloc(length + 1); 
  63.         if (str != NULL
  64.         { 
  65.             va_copy(argsCopy, args); 
  66.             vsprintf(str, fmt, argsCopy); 
  67.             va_end(argsCopy); 
  68.         } 
  69.         else 
  70.         { 
  71.             // Failed to allocate log message, drop it. 
  72.             return
  73.         } 
  74.         callbackData->managedCallback(callbackData->managedData, level, ctx, str); 
  75.         free(str); 
  76.     } 
  77. void sendLog(void* data, int level, const void* ctx, const char* fmt, ...) 
  78.     va_list va; 
  79.     va_start(va, fmt); 
  80.     InteropCallback(data, level, ctx, fmt, va); 
  81.     va_end(va); 
  82. int main(int argc, char** argv) 
  83.     /*注冊(cè)一個(gè)回調(diào)函數(shù)結(jié)構(gòu)體,level等級(jí)為L(zhǎng)IBVLC_WARNING 只要發(fā)送的log等級(jí)大于等于LIBVLC_WARNING次啊會(huì)觸發(fā)回調(diào)函數(shù)*/ 
  84.     void* callbackData = makeCallbackData(formattedLogCallback, "context", LIBVLC_WARNING); 
  85.     /*發(fā)送四個(gè)等級(jí)的消息*/ 
  86.     sendLog(callbackData, LIBVLC_DEBUG, NULL"This should not be displayed : %s\n","debug"); 
  87.     sendLog(callbackData, LIBVLC_NOTICE, NULL"This should not be displayed : %s\n""notick"); 
  88.     sendLog(callbackData, LIBVLC_WARNING, NULL"This message level is : %s\n""warning"); 
  89.     sendLog(callbackData, LIBVLC_ERROR, NULL"Hello, %s ! You should see %ld message here : %s\n""World", 1, "warning message"); 
  90.  
  91.     free(callbackData); 
  92.     return 0; 

輸出                                                                                                                                                                                                                

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

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

然后在發(fā)送log的時(shí)候根據(jù)level判斷是否執(zhí)行回調(diào)函數(shù),順便格式化log信息

 

責(zé)任編輯:武曉燕 來源: 編程學(xué)習(xí)基地
相關(guān)推薦

2011-05-13 17:25:34

C

2012-09-18 13:26:39

CC++

2009-06-29 15:23:00

2011-08-01 17:11:43

Objective-C 函數(shù)

2010-02-03 15:06:02

C++可變參數(shù)表

2023-12-04 18:31:59

C語言函數(shù)

2022-07-14 16:35:11

C語言編程語言

2017-04-11 08:36:09

iOS編譯應(yīng)用

2010-01-15 18:50:37

C++語言

2022-07-01 11:56:54

C語言C++編程語言

2011-03-30 11:01:13

C語言隨機(jī)

2024-01-17 06:23:35

SwiftTypeScript定義函數(shù)

2024-06-05 16:22:11

2010-07-12 21:44:51

HART協(xié)議

2024-08-14 18:18:47

2010-09-08 11:59:38

藍(lán)牙協(xié)議棧

2010-02-04 13:39:44

C++數(shù)組參數(shù)

2010-12-21 14:21:36

線程C#

2022-01-17 07:32:34

Java參數(shù)方法

2011-06-15 10:53:05

C語言
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 成人av一区 | 五月激情久久 | 成人在线视频免费看 | 久久这里有精品 | 91超碰在线| 午夜网站视频 | 国产在线h | 国产综合精品一区二区三区 | 久久只有精品 | 六月色婷 | 欧美国产精品一区二区三区 | 午夜精品一区二区三区在线播放 | 免费国产视频在线观看 | 人干人操 | 国产精品久久久久久久久免费丝袜 | 另类专区成人 | 日韩免费视频 | 国产黄色大片 | 91精品国产91久久久久久最新 | 日韩国产精品一区二区三区 | 亚洲精品中文字幕中文字幕 | 中国免费黄色片 | 欧美亚洲另类丝袜综合网动图 | 久久久这里只有17精品 | 99re在线视频 | 国产精品毛片一区二区在线看 | 精品国产乱码久久久久久老虎 | 日韩欧美一区二区在线播放 | av香蕉| 久久99久久久久 | 久久久久久网 | 成人在线视频免费观看 | 亚洲精品久久久久久一区二区 | 午夜精品 | www.国产一区 | 一区二区三区电影在线观看 | 国产精品久久久久久 | 欧美a免费| 亚洲 精品 综合 精品 自拍 | 精品日本中文字幕 | 亚洲欧洲日韩精品 中文字幕 |