相关源码
#include <stdio.h>
#include <time.h>
#include <stdarg.h>
#include <sys/time.h>
#include "utils.h"
/**
* Logger is used to write any kind of messages to file descriptors.
* Useful with debugging etc.
*
* @param file file descriptor to which messages should be written
* @param level level of message (defined in header: DEBUG, INFO, WARN, ERROR)
* @param format exactly as in printf
*/
void logger(FILE *file, int level, const char *format, ...)
{
va_list ap;
char time[255], *level_str;
struct timeval tp;
struct tm *tms;
if (level == ERROR)
level_str = "ERROR";
else if (level == WARN)
level_str = "WARN";
else if (level == INFO)
level_str = "INFO";
else if (level == DEBUG)
level_str = "DEBUG";
va_start(ap, format);
gettimeofday(&tp, NULL);
tms = localtime(&(tp.tv_sec));
strftime(time, sizeof(time), "%H:%M:%S", tms);
fprintf(file, "[%-5s][%s.%03ld] ", level_str, time, tp.tv_usec / 1000);
vfprintf(file, format, ap);
fprintf(file, "\n");
va_end(ap);
}
源码函数解析
utils.c定义logger()函数
函数名: logger
功 能: 将特定信息写入相应文件中
用 法:
void logger(FILE *file, int level, const char *format, ...)
logger()函数中的陌生函数或类型学
- va_ist,va_start(),va_end()
- struct timeval,struct tm
- gettimeofday(),localtime()
- strftime()
- fprintf()
- vfprintf()
va_list,va_start(),va_end()
用指针参数解决不定数目函数参数问题,
(1)va_list
定义了一个指针arg_ptr, 用于指示可选的参数.
(2)va_start(arg_ptr, argN)
使参数列表指针arg_ptr指向函数参数列表中的第一个可选参数,argN是位于第一个可选参数之前的固定参数, 或者说最后一个固定参数.如有一va函数的声明是
void va_test(char a, char b, char c, ...)
则它的固定参数依次是a,b,c, 最后一个固定参数argN为c, 因此就是
va_start(arg_ptr, c)
(3)va_arg(arg_ptr, type)
返回参数列表中指针arg_ptr所指的参数, 返回类型为type. 并使指针arg_ptr指向参数列表中下一个参数.返回的是可选参数, 不包括固定参数.
(4)va_end(arg_ptr)
清空参数列表, 并置参数指针arg_ptr无效.
(注:va在这里是variable-argument(可变参数)的意思. 这些宏定义在stdarg.h中,所以用到可变参数的程序应该包含这个头文件)
struct timeval,struct tm
struct timeval 结构体
该结构体是Linux系统中定义,struct timeval结构体在time.h中的定义为:
struct timeval
{
__time_t tv_sec; /* Seconds. */
__suseconds_t tv_usec; /* Microseconds. */
};
其中,tv_sec为Epoch(1970年1月1日00:00:00 UTC)到创建struct timeval时的秒数,tv_usec为微秒数,即秒后面的零头。
struct tm 结构体
该结构体是Linux系统中定义,struct timeval结构体在time.h中的定义为:
struct tm
{
int tm_sec; /* Seconds. [0-60] (1 leap second) */
int tm_min; /* Minutes. [0-59] */
int tm_hour; /* Hours. [0-23] */
int tm_mday; /* Day. [1-31] */
int tm_mon; /* Month. [0-11] */
int tm_year; /* Year - 1900. */
int tm_wday; /* Day of week. [0-6] */
int tm_yday; /* Days in year.[0-365] */
int tm_isdst; /* DST. [-1/0/1]*/
};
linux下存储时间常见的有两种存储方式,一个是从1970年到现在经过了多少秒,一个是用一个结构来分别存储年月日时分秒的。time_t 这种类型就是用来存储从1970年到现在经过了多少秒,更精确一点,可以用结构struct timeval,它精确到微妙。而直接存储年月日的是一个结构体struct tm。
gettimeofday();localtime()
下面介绍一下我们常用的时间函数:
**char *asctime(const struct tm* timeptr);**
将结构中的信息转换为真实世界的时间,以字符串的形式显示
**char *ctime(const time_t *timep);**
将timep转换为真实世界的时间,以字符串显示,它和asctime不同就在于传入的参数形式不一样
**double difftime(time_t time1, time_t time2);**
返回两个时间相差的秒数
**int gettimeofday(struct timeval *tv, struct timezone *tz);**
返回当前距离1970年的秒数和微妙数,后面的tz是时区,一般不用
gettimeofday()会把目前的时间用timeval结构体返回,当地时区的信息则放到tz所指的timezone结构体中。
timezone 结构定义为:
struct timezone{
int tz_minuteswest;/*和greenwich 时间差了多少分钟*/
int tz_dsttime;/*type of DST correction*/
}
在gettimeofday()函数中tv或者tz都可以为空。如果为空则就不返回其对应的结构体。
函数执行成功后返回0,失败后返回-1,错误代码存于error中。
**struct tm* gmtime(const time_t *timep);**
将time_t表示的时间转换为没有经过时区转换的UTC时间,是一个struct tm结构指针
**stuct tm* localtime(const time_t *timep);**
函数说明:localtime()将参数timep 所指的time_t 结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果由结构tm 返回。此函数返回的时间日期已经转换成当地时区。和gmtime类似,但是它是经过时区转换的时间。
返回值:返回结构tm 代表目前的当地时间。
**time_t mktime(struct tm* timeptr);**
将struct tm 结构的时间转换为从1970年至今的秒数
**time_t time(time_t *t);**
取得从1970年1月1日至今的秒数。
strftime()
linux 时间格式化函数strftime:
函数是时间日期的格式控制函数。strftime将一个struct tm结构格式化为一个字符串。
**函数原型:
size_t strftime(char *s,size_t maxsize,char *format,const struct tm *timeptr)
strftime函数对timeptr指向的tm结构所代表的时间和日期进行格式编排,其结果放在字符串s中。最多向字符串s中存放maxsize个字符。该函数返回向s指向的字符串中放置的字符数。格式字符串format用来对写入字符串的字符进行控制,它包含着将被传送到字符串里去的普通字符以及编排时间和日期格式的转换控制符。
此外,strptime()函数与strftime()功能上刚好相反,则是将一个字符串格式化为一个struct tm结构。关于**strftime()和strptime()**d的详细介绍请看参考文章
fprintf()
fprintf()函数主要用于格式化信息输出到指定的文件流中返回值:成功则返回输出的字节数,失败返回eof;
int fprintf( FILE *stream, const char *format, ... );
fprintf()函数根据指定的format(格式)发送信息(参数)到由stream(流)指定的文件.因此fprintf()可以使得信息输出到指定的文件.fprintf()的返回值是输出的字符数,发生错误时返回一个负值.
函数原型:
`/* Write formatted output to STREAM.This function is a possible cancellation point and therefore not marked with __THROW. */
extern int fprintf (FILE *__restrict __stream,__const char *__restrict __format, ...);`
关于fprintf的详细介绍请参考文章
vfprintf()
函数名: vfprintf
功 能: 送格式化输出到一流中,vfprintf()会根据参数format字符串来转换并格式化va_list(可变参数的)数据,然后将结果输出到参数stream指定的文件中,直到出现字符串结束(‘\0’)为止。
用 法:
int vfprintf(FILE *stream, char *format,
va_list param);
返回值: 成功则返回实际输出的字符数,失败则返回-1,错误原因存于errno中。
函数原型:
`/* Write formatted output to S from argument list ARG.This function is a possible cancellation point and therefore not marked with __THROW. */
extern int vfprintf (FILE *__restrict __s, __const char *__restrict __format, _G_va_list __arg);`
关于vfprintf的详细介绍请看参考文章