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_DEBUG
void EM_LOG(int level, const char* function, int line, const char* fmt, ...);
#define EMLOG(level, fmt...) EM_LOG(level, __FUNCTION__, __LINE__, fmt)
#endif
log.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_LOG
printf("[%s] [%s : %d] %s\n", EM_LOGLevelGet(level), function, line, buf);
#endif
va_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;
}
本文深入探讨C语言中可变参数的使用方法与原理,包括可变参数的要点、应用实例、宏定义解析以及简易log实现。通过具体代码示例,详细讲解了如何在函数中处理数量不定的参数。
937

被折叠的 条评论
为什么被折叠?



