赞
踩
stdarg.h
可变参数宏实现prinft()
即为典型的可变参数函数,它除了有一个参数 format 固定以外,后面跟的参数的个数和类型是可变的。#include <stdarg.h>
int printf(const char *fmt, ...)
{
char printf_buf[1024];
va_list args; /* args为定义的一个指向可变参数的变量,va_list以及下边要用到的va_start,va_end都是是在定义
可变参数函数中必须要用到宏, 在stdarg.h头文件中定义 */
int printed;
va_start(args, fmt); //初始化args的函数,使其指向可变参数的第一个参数,fmt是可变参数的前一个参数
printed = vsprintf(printf_buf, fmt, args);
va_end(args); //结束可变参数的获取
puts(printf_buf);
return printed;
}
va_list
----用于定义一个va_list类型的变量,为后面的扩展可变参列表做准备
eg: va_list args;
va_start
—用于初始化va_list类型的变量
eg: va_start(args,fmt);
表示进行扩展参数,其中 args 为va_list类型的变量,fmt为离可变参(…)最近的一个确定参数
va_arg
—从变参列表中获取一个参数
eg: type va_arg(args,data_type)
— data_type表示数据类型
—> int b = va_arg(pvar,int);
va_end
—关闭变参扩展,进行后续的内存回收工作 eg : va_end(pvar)
/* --sum.cpp-- 可变参数宏实现求任意个整形值得和 */ #include <stdarg.h> #include <iostream> using namespace std; int sum(int count, ...){ //count 表示可变参数个数 va_list ap; //声明一个va_list变量 va_start(ap, count); //初始化,第二个参数为最后一个确定的形参 int sum = 0; for(int i = 0; i < count; i++) sum += va_arg(ap, int); //读取可变参数,第二个参数为可变参数的类型 va_end(ap); //清理工作 return sum; } int main(){ cout << sum(3,1,2,3); // 第一个3为参数个数 return 0; }
使用事项:
va_end
进行清理工作;因为可变参的机制类似于动态开辟空间,而va_end就相当于内存回收;va_start
初始化 va_list 变量,重新遍历形参表;initializer_list 是C++11新标准中引入的一个标准库类型,与 vector 等容器一样initializer_list也支持begin()和end()操作,返回指向首元素的迭代器和尾后迭代器。initializer_list在同名头文件中声明,其实现由编译器支持。
说明:
initializer_list
模板代表可变参数列表;void func(char c, initializer_list <int> il, double d);
/* --sum.cpp-- 利用initializer_list模板实现求和 */ #include <iostream> using namespace std; #include <initializer_list> int sum(initializer_list<int> il){ int sum = 0; for(auto p = il.begin(); p != il.end(); p++) //使用迭代器访问参数 sum += *p; return sum; } int main(){ cout << sum({1,2,3}); // 参数以列表形式传递 return 0; }
参考:
https://blog.csdn.net/Clark_Sev/article/details/89500808
https://blog.csdn.net/qq_35280514/article/details/51637920
#include <stdio.h> #include <stdarg.h> // 可变参数宏实现 #define OPEN_LOG 1 // 声明是否打开日志输出 #define LOG_LEVEL LOGLEVEL_INFO // 声明当前程序的日志等级状态,只输出等级等于或高于该值的内容 typedef enum{ // 日志等级,越往下等级越高 LOGLEVEL_DEBUG = 0, LOGLEVEL_INFO, LOGLEVEL_WARN, LOGLEVEL_ERROR, }E_LOGLEVEL; char *EM_logLevelGet(const int level){ // 得到当前输入等级level的字符串 if(level == LOGLEVEL_DEBUG){ return (char*)"DEBUG"; }else if (level == LOGLEVEL_INFO ){ return (char*)"INFO"; }else if (level == LOGLEVEL_WARN ){ return (char*)"WARN"; }else if (level == LOGLEVEL_ERROR ){ return (char*)"ERROR"; }else{ return (char*)"UNKNOWN"; } } void EM_log(const int level, const char* fun, const int line, const char *fmt, ...){ // 日志输出函数(可变参数) #ifdef OPEN_LOG // 判断开关 va_list arg; va_start(arg, fmt); // fmt为最后一个确定的形参 char buf[1 + vsnprintf(NULL, 0, fmt, arg)]; // 创建缓存字符数组,长度需+1(结束符) // vsnprintf(NULL, 0, fmt, arg)返回arg 中的字符个数(不包含终止符) vsnprintf(buf, sizeof(buf), fmt, arg); // 赋值 fmt 格式的 arg 到 buf va_end(arg); if(level >= LOG_LEVEL){ // 判断当前日志等级,与程序日志等级状态对比 printf("[%s]\t[%s %d]: %s \n", EM_logLevelGet(level), fun, line, buf); } #endif } #define EMlog(level, fmt...) EM_log(level, __FUNCTION__, __LINE__, fmt) // 宏定义,隐藏形参 int main(){ int a = 1, b = 2; printf("Start log test: \n"); EMlog(LOGLEVEL_DEBUG, "debug ing"); // 当前语句输出等级为 LOGLEVEL_DEBUG EMlog(LOGLEVEL_INFO, "info ing"); EMlog(LOGLEVEL_WARN, "warn ing"); EMlog(LOGLEVEL_ERROR, "error ing"); printf("当前代码所在函数为:\t%s\n",__FUNCTION__); // 调用宏__FUNCTION__得到当前代码所在函数 printf("当前代码所在行为\t:%d\n",__LINE__); // 调用宏__LINE__得到当前代码所在行 return 0; }
log.h
#ifndef _EM_LOG_H_ // 多个文件引用时,不能重复定义 #define _EM_LOG_H_ #include <stdarg.h> #define OPEN_LOG 1 // 声明是否打开日志输出 #define LOG_LEVEL LOGLEVEL_INFO // 声明当前程序的日志等级状态,只输出等级等于或高于该值的内容 #define LOG_SAVE 0 // 可补充日志保存功能 typedef enum{ // 日志等级,越往下等级越高 LOGLEVEL_DEBUG = 0, LOGLEVEL_INFO, LOGLEVEL_WARN, LOGLEVEL_ERROR, }E_LOGLEVEL; void EM_log(const int level, const char* fun, const int line, const char *fmt, ...); #define EMlog(level, fmt...) EM_log(level, __FUNCTION__, __LINE__, fmt) // 宏定义,隐藏形参 #endif
#include <stdio.h> #include "log.h" char *EM_logLevelGet(const int level){ // 得到当前输入等级level的字符串 if(level == LOGLEVEL_DEBUG){ return (char*)"DEBUG"; }else if (level == LOGLEVEL_INFO ){ return (char*)"INFO"; }else if (level == LOGLEVEL_WARN ){ return (char*)"WARN"; }else if (level == LOGLEVEL_ERROR ){ return (char*)"ERROR"; }else{ return (char*)"UNKNOWN"; } } void EM_log(const int level, const char* fun, const int line, const char *fmt, ...){ // 日志输出函数 #ifdef OPEN_LOG // 判断开关 va_list arg; va_start(arg, fmt); char buf[1 + vsnprintf(NULL, 0, fmt, arg)]; // 创建缓存字符数组,长度需+1(结束符) vsnprintf(buf, sizeof(buf), fmt, arg); // 赋值 ftm 格式的 arg 到 buf va_end(arg); if(level >= LOG_LEVEL){ // 判断当前日志等级,与程序日志等级状态对比 printf("[%s]\t[%s %d]: %s \n", EM_logLevelGet(level), fun, line, buf); } #endif }
app.c
#include <stdio.h> #include "log.h" int main(){ int a = 1, b = 2; printf("Start log test: \n"); EMlog(LOGLEVEL_DEBUG, "debug ing"); // 当前语句输出等级为 LOGLEVEL_DEBUG EMlog(LOGLEVEL_INFO, "info ing"); EMlog(LOGLEVEL_WARN, "warn ing"); EMlog(LOGLEVEL_ERROR, "error ing"); printf("当前代码所在函数为:\t%s\n",__FUNCTION__); // 调用宏__FUNCTION__得到当前代码所在函数 printf("当前代码所在行为\t:%d\n",__LINE__); // 调用宏__LINE__得到当前代码所在行 return 0; }
gcc app.c log.c -o app
编译
#include <stdio.h> #include <stdlib.h> typedef struct { int output; int a; int b; int (*TeseFunc)(int, int); // 两个整数形参的函数指针,测试目标函数 int line; // 函数所在行 }T_Test; // 结构体作为函数返回值(新建结构体) T_Test *addFunc(int (*TeseFunc)(int, int), int a, int b, int output, int line){ T_Test *m_Test = (T_Test *)malloc(sizeof(T_Test)); // 动态申请 m_Test->a = a; m_Test->b = b; m_Test->TeseFunc = TeseFunc; m_Test->output = output; m_Test->line = line; return m_Test; } // 宏定义函数,缺省line #define addFunc(TeseFunc, a, b, output) addFunc(TeseFunc, a, b, output, __LINE__) void runTest(T_Test *p_Test){ if(p_Test != NULL){ int count = p_Test->TeseFunc(p_Test->a, p_Test->b); if(count == p_Test->output){ printf("success \n"); } else{ printf("[LINE: %d] fail %d != %d\n", p_Test->line, count, p_Test->output); } free(p_Test); // 释放内存 } } int add(int a, int b){ return a+b; } int main(){ printf("Test app start.\n"); T_Test *m_Test = addFunc(add, 1, 2, 4); runTest(m_Test); return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。