當前位置:
首頁 >
函数中的可变参数
發布時間:2025/4/5
28
豆豆
文章目錄
- 1 可變參數的使用
- 1.1 可變參數的要點
- 1.2 可變參數的應用
- 2 可變參數原理分析
- 2.1 可變參數中設計的各個宏
- 3 宏中如何傳遞可變參
- 4 可變參的應用:簡易log實現
1 可變參數的使用
1.1 可變參數的要點
C語言中可以定義參數可變的函數。
參數可變函數的實現依賴于stdarg.h頭文件:
- va_list:參數集合
- va_arg:取具體參數值
- va_start:標識參數訪問的開始
- va_end:標識參數訪問的結束
可變參數的限制:
- 可變參數必須從頭到尾按照順序逐個訪問,無法直接訪問中間的參數值。
- 參數列表中至少要存在一個確定的命名參數。
- 可變參數函數無法確定實際存在的參數的數量。
- 可變參數函數無法確定參數的實際類型。
注意:va_arg中如果指定了錯誤的類型,那么結果是不可預測的。
1.2 可變參數的應用
編寫函數計算平均值:
#include <stdio.h> #include <stdarg.h>float average(int n, ...) {va_list args;int i = 0;float sum = 0;va_start(args, n);for(i=0; i<n; i++){sum += va_arg(args, int);}va_end(args);return sum / n; }int main() {printf("%f\n", average(5, 1, 2, 3, 4, 5));printf("%f\n", average(4, 1, 2, 3, 4));return 0; }2 可變參數原理分析
2.1 可變參數中設計的各個宏
知道了參數是如傳遞的及入棧順序,分析如下代碼就很簡單了。原理性的實現代碼如下:
typedef char * va_list; #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) // 這里是進行內存對齊,32位的實現,如果是64位則不是這種實現#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) #define va_arg(ap,t) ( *(t *)( ap=ap + _INTSIZEOF(t), ap- _INTSIZEOF(t)) ) #define va_end(ap) ( ap = (va_list)0 )3 宏中如何傳遞可變參
在c99語法中支持可變參,如下:
void EM_LOG(int level, const char* function, int line, const char* fmt, ...);#define EMLOG(level, fmt...) EM_LOG(level, __FUNCTION__, __LINE__, fmt)4 可變參的應用:簡易log實現
實現較簡單,不多說,直接看代碼:
log.h:
#ifndef _LOG_H #define _LOG_H#include <stdio.h> #include <stdarg.h> #include <string.h> #include <stdlib.h>typedef enum {LOG_DEBUG = 1,LOG_INFO,LOG_WARNING,LOG_ERROR }LOG_LEVEL_E;#define OPEN_LOG 1 #define LOG_LEVEL LOG_DEBUGvoid EM_LOG(int level, const char* function, int line, const char* fmt, ...);#define EMLOG(level, fmt...) EM_LOG(level, __FUNCTION__, __LINE__, fmt)#endiflog.cpp:
#include "log.h"const char* EM_LOGLevelGet(int level) {if (level == LOG_DEBUG){return "DEBUG";}else if (level == LOG_INFO){return "INFO";}else if (level == LOG_WARNING){return "WARNING";}else if (level == LOG_ERROR){return "ERROR";}return "UNKOWN"; }void EM_LOG(int level, const char* function, int line, const char* fmt, ...) {va_list arg;int len = 0;va_start(arg, fmt);len = vsnprintf(NULL, 0, fmt, arg) + 1;char* buf = (char*)malloc(len);memset(buf, 0, len);vsnprintf(buf, len, fmt, arg);#ifdef OPEN_LOGprintf("[%s] [%s : %d] %s\n", EM_LOGLevelGet(level), function, line, buf); #endifva_end(arg); }main.c:
#include "log.h"int main(void) {EMLOG(LOG_DEBUG, "debug...");EMLOG(LOG_INFO, "info...");EMLOG(LOG_WARNING, "warning...");EMLOG(LOG_ERROR, "error...");return 0; }總結