自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

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

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

 [[373935]]

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

概述

C語(yǔ)言中沒(méi)有函數(shù)重載,解決不定數(shù)目函數(shù)參數(shù)問(wèn)題變得比較麻煩;

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

var_list可變參數(shù)介紹

VA_LIST 是在C語(yǔ)言中解決變參問(wèn)題的一組宏,原型:

  1. typedef char* va_list; 

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

除了var_list ,我們還需要幾個(gè)宏來(lái)實(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 )                  // 將指針置為無(wú)效 

簡(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è)入棧過(guò)程,堆棧地址不斷遞減,

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

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

說(shuō)這么多直接上代碼演示吧..

  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ì)說(shuō)就這?這么簡(jiǎn)單,指定第一個(gè)參數(shù)是后面參數(shù)的總數(shù)就可以了,這還不隨隨便玩

別著急,精彩的來(lái)了,「可變參數(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é)任編輯:武曉燕 來(lái)源: 編程學(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語(yǔ)言函數(shù)

2022-07-14 16:35:11

C語(yǔ)言編程語(yǔ)言

2024-01-17 06:23:35

SwiftTypeScript定義函數(shù)

2022-07-01 11:56:54

C語(yǔ)言C++編程語(yǔ)言

2017-04-11 08:36:09

iOS編譯應(yīng)用

2010-01-15 18:50:37

C++語(yǔ)言

2011-03-30 11:01:13

C語(yǔ)言隨機(jī)

2022-01-17 07:32:34

Java參數(shù)方法

2011-06-15 10:53:05

C語(yǔ)言

2010-02-04 13:39:44

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

2021-02-06 07:26:06

C++編程可變模板參數(shù)

2010-12-21 14:21:36

線程C#

2024-08-14 18:18:47

2010-09-08 11:59:38

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

2010-07-13 13:30:07

HART協(xié)議
點(diǎn)贊
收藏

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