函数中的可变参数
文章目錄
- 1 可變參數(shù)的使用
- 1.1 可變參數(shù)的要點(diǎn)
- 1.2 可變參數(shù)的應(yīng)用
- 2 可變參數(shù)原理分析
- 2.1 可變參數(shù)中設(shè)計(jì)的各個(gè)宏
- 3 宏中如何傳遞可變參
- 4 可變參的應(yīng)用:簡(jiǎn)易log實(shí)現(xiàn)
1 可變參數(shù)的使用
1.1 可變參數(shù)的要點(diǎn)
C語(yǔ)言中可以定義參數(shù)可變的函數(shù)。
參數(shù)可變函數(shù)的實(shí)現(xiàn)依賴于stdarg.h頭文件:
- va_list:參數(shù)集合
- va_arg:取具體參數(shù)值
- va_start:標(biāo)識(shí)參數(shù)訪問的開始
- va_end:標(biāo)識(shí)參數(shù)訪問的結(jié)束
可變參數(shù)的限制:
- 可變參數(shù)必須從頭到尾按照順序逐個(gè)訪問,無法直接訪問中間的參數(shù)值。
- 參數(shù)列表中至少要存在一個(gè)確定的命名參數(shù)。
- 可變參數(shù)函數(shù)無法確定實(shí)際存在的參數(shù)的數(shù)量。
- 可變參數(shù)函數(shù)無法確定參數(shù)的實(shí)際類型。
注意:va_arg中如果指定了錯(cuò)誤的類型,那么結(jié)果是不可預(yù)測(cè)的。
1.2 可變參數(shù)的應(yīng)用
編寫函數(shù)計(jì)算平均值:
#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 可變參數(shù)原理分析
2.1 可變參數(shù)中設(shè)計(jì)的各個(gè)宏
知道了參數(shù)是如傳遞的及入棧順序,分析如下代碼就很簡(jiǎn)單了。原理性的實(shí)現(xiàn)代碼如下:
typedef char * va_list; #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) // 這里是進(jìn)行內(nèi)存對(duì)齊,32位的實(shí)現(xiàn),如果是64位則不是這種實(shí)現(xiàn)#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語(yǔ)法中支持可變參,如下:
void EM_LOG(int level, const char* function, int line, const char* fmt, ...);#define EMLOG(level, fmt...) EM_LOG(level, __FUNCTION__, __LINE__, fmt)4 可變參的應(yīng)用:簡(jiǎn)易log實(shí)現(xiàn)
實(shí)現(xiàn)較簡(jiǎn)單,不多說,直接看代碼:
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; }總結(jié)