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

C語言可變參數的原理和應用

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

 [[373935]]

本文轉載自微信公眾號「編程學習基地  」,作者deroy  。轉載本文請聯系編程學習基地  公眾號。 

概述

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

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

var_list可變參數介紹

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

  1. typedef char* va_list; 

其實就是個char*類型變量

除了var_list ,我們還需要幾個宏來實現可變參數

「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) )//第一個可選參數地址 
  3. #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )//下一個參數地址 
  4. #define va_end(ap)    ( ap = (va_list)0 )                  // 將指針置為無效 

簡單使用可變參數

  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; 

啊這..

可變參數原理

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

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

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

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

  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);            //打印參數i在堆棧中的地址 
  15.     printf("arg_ptr = %p\n", arg_ptr);  //打印va_start之后arg_ptr地址,比參數i的地址高sizeof(int)個字節 
  16.     /*  這時arg_ptr指向下一個參數的地址 */ 
  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的地址,比調用va_arg前高sizeof(int)個字節 
  23.  
  24.     next = *((int*)arg_ptr); 
  25.     ReturnValue += next
  26.     /*  這時arg_ptr指向下一個參數的地址 */ 
  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 

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

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

  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 

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

別著急,精彩的來了,「可變參數的應用」

可變參數應用:實現log打印

  1. #include <stdarg.h> 
  2. #include <stdio.h> 
  3. #include <stdlib.h> 
  4. /*定義一個回調函數指針*/ 
  5. typedef void (*libvlcFormattedLogCallback)(void* data, int level, const void* ctx, const char* message); 
  6. enum libvlc_log_level {  
  7.     LIBVLC_DEBUG = 0,       //調試 
  8.     LIBVLC_NOTICE = 2,      //普通 
  9.     LIBVLC_WARNING = 3,     //警告 
  10.     LIBVLC_ERROR = 4 }      //錯誤 
  11. /*定義一個回調函數結構體*/ 
  12. typedef struct CallbackData { 
  13.     void* managedData; 
  14.     libvlcFormattedLogCallback managedCallback; 
  15.     int minLogLevel;        //log 級別 
  16. } CallbackData; 
  17.  
  18. /*構造回調函數結構體*/ 
  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. /*回調函數*/ 
  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信息并執行回調函數*/ 
  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.     /*注冊一個回調函數結構體,level等級為LIBVLC_WARNING 只要發送的log等級大于等于LIBVLC_WARNING次啊會觸發回調函數*/ 
  84.     void* callbackData = makeCallbackData(formattedLogCallback, "context", LIBVLC_WARNING); 
  85.     /*發送四個等級的消息*/ 
  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 

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

然后在發送log的時候根據level判斷是否執行回調函數,順便格式化log信息

 

責任編輯:武曉燕 來源: 編程學習基地
相關推薦

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 函數

2010-02-03 15:06:02

C++可變參數表

2023-12-04 18:31:59

C語言函數

2022-07-14 16:35:11

C語言編程語言

2010-01-15 18:50:37

C++語言

2022-07-01 11:56:54

C語言C++編程語言

2017-04-11 08:36:09

iOS編譯應用

2011-03-30 11:01:13

C語言隨機

2024-01-17 06:23:35

SwiftTypeScript定義函數

2022-01-17 07:32:34

Java參數方法

2011-06-15 10:53:05

C語言

2024-06-05 16:22:11

2010-07-12 21:44:51

HART協議

2010-12-21 14:21:36

線程C#

2010-02-04 13:39:44

C++數組參數

2024-08-14 18:18:47

2010-09-08 11:59:38

藍牙協議棧
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产伦精品一区二区三区精品视频 | www.av在线| 欧美一区精品 | 91综合网 | 伊人操| 亚洲男女视频在线观看 | 精品国产乱码久久久久久果冻传媒 | 黄色大片在线视频 | 亚洲精品久久久9婷婷中文字幕 | 国产成人精品免高潮在线观看 | 亚洲国产成人精品女人久久久 | 99久久精品国产毛片 | 日日操操操| 亚洲美女一区二区三区 | 国产精品免费在线 | 国产精品网址 | 久久国产精品-久久精品 | 久久久久国产精品一区二区 | 成人h视频| 国产精品综合色区在线观看 | 久久亚洲国产精品 | 国产精品久久久久久久久免费相片 | 在线视频亚洲 | 国产精品视频500部 a久久 | 欧美男人的天堂 | 久久久一区二区 | 欧美日韩福利视频 | 久草综合在线视频 | 欧美a区 | 成人三级视频 | 国产精品毛片一区二区三区 | 国产日韩一区二区三免费 | 欧美精品一区三区 | 老牛影视av一区二区在线观看 | 国产精品自拍视频 | 日韩欧美亚洲 | 欧美久久久久久 | 欧美一二三区 | 成年人在线观看视频 | 伊人春色成人网 | 免费久草 |