현재 시각을 측정하는 손쉬운 방법은 gettimeofday()를 이용하는 것으로,
이때 struct timeval 구조체를 이용하게 된다.
<API>
int gettimeofday(struct timeval *tv, struct timezone *tz);
<example>
struct timeval tv;
if (!gettimeofday(&tv, NULL)) fprintf(stderr, "%s error at %d\n", __FUNCTION__, __LINE__);
그리고 /usr/include/sys/time.h 파일을 보면 다음과 같은 편리한 macro를 제공함을 알 수 있다.
__USE_BSD 가 언제 #define 되는지 모르겟지만 이용 할 수 있었다.
stuct timeval 에 sec 부분과 usec 부분으로 분리되어 있는데 아래 3개 macro는 유용할 것이다.
timercmp(a, b, CMP)
timeradd(a, b, result)
timersub(a, b, result)
예를 들어 현재 시각을 매번 측정하여 그 차이를 위의 timersub를 통해 손쉽게 계산할 수 있고,
그 차이를 timeradd를 통해 손쉽게 계속 더해갈 수 있다.
#ifdef __USE_BSD
/* Convenience macros for operations on timevals.
NOTE: `timercmp' does not work for >= or <=. */
# define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
# define timerclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0)
# define timercmp(a, b, CMP) \
(((a)->tv_sec == (b)->tv_sec) ? \
((a)->tv_usec CMP (b)->tv_usec) : \
((a)->tv_sec CMP (b)->tv_sec))
# define timeradd(a, b, result) \
do { \
(result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
(result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
if ((result)->tv_usec >= 1000000) \
{ \
++(result)->tv_sec; \
(result)->tv_usec -= 1000000; \
} \
} while (0)
# define timersub(a, b, result) \
do { \
(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
(result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
if ((result)->tv_usec < 0) { \
--(result)->tv_sec; \
(result)->tv_usec += 1000000; \
} \
} while (0)
#endif /* BSD */
그런데 struct timeval 을 그대로 이용할 때는 불편할 때가 있다.
예를 들어 sec을 일부와 usec의 일부만을 출력하거나
다른 일반 int type으로 저장한 시간과 비교할 때가 그럴 수 있을 것이다.
(어디까지나 선택사항이지만) 이때는 struct timeval 을 long long 으로 변환해서 저장하는 것이 편하다.
아래와 같이 long long time 에 저장하는 것이다.
time = tv.tv_sec * 1000000LL + tv.tv_usec;
참고적으로 혹시 전환 과정에서 data 손실을 우려할 수 있으나 그렇지 않다.
long long type이 보통 8byte 이고, struct timeval의 tv_sec 과 tv_usec 이 각각 4byte 인데,
실제로는 tv_usec의 값은 최대 10^6 - 1 로서, 이는 2진수 값으로 20bit 이하이다.
따라서 20bit 인 2.5byte를 shift 하더라도 데이터 손실이 없는 것이다.
아래는 관련해서 테스트한 소스 코드이며,
struct timeval : 1270047284.534099
long long : 1270047284534099
실행결과 바로 위와 같이 두 값이 같음을 알 수 있다.
#include <stdio.h>
#include <sys/time.h>
int main(int argc, char *argv[])
{
struct timeval tv;
long long time;
if (gettimeofday(&tv, NULL)) fprintf(stderr, "%s error at %d\n", __FUNCTION__, __LINE__);
time = tv.tv_sec * 1000000LL + tv.tv_usec;
printf("struct timeval : %d.%-6d\n", (int)tv.tv_sec, (int)tv.tv_usec);
printf("long long : %lld\n", time);
return 0;
}
이때 struct timeval 구조체를 이용하게 된다.
<API>
int gettimeofday(struct timeval *tv, struct timezone *tz);
<example>
struct timeval tv;
if (!gettimeofday(&tv, NULL)) fprintf(stderr, "%s error at %d\n", __FUNCTION__, __LINE__);
그리고 /usr/include/sys/time.h 파일을 보면 다음과 같은 편리한 macro를 제공함을 알 수 있다.
__USE_BSD 가 언제 #define 되는지 모르겟지만 이용 할 수 있었다.
stuct timeval 에 sec 부분과 usec 부분으로 분리되어 있는데 아래 3개 macro는 유용할 것이다.
timercmp(a, b, CMP)
timeradd(a, b, result)
timersub(a, b, result)
예를 들어 현재 시각을 매번 측정하여 그 차이를 위의 timersub를 통해 손쉽게 계산할 수 있고,
그 차이를 timeradd를 통해 손쉽게 계속 더해갈 수 있다.
#ifdef __USE_BSD
/* Convenience macros for operations on timevals.
NOTE: `timercmp' does not work for >= or <=. */
# define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
# define timerclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0)
# define timercmp(a, b, CMP) \
(((a)->tv_sec == (b)->tv_sec) ? \
((a)->tv_usec CMP (b)->tv_usec) : \
((a)->tv_sec CMP (b)->tv_sec))
# define timeradd(a, b, result) \
do { \
(result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
(result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
if ((result)->tv_usec >= 1000000) \
{ \
++(result)->tv_sec; \
(result)->tv_usec -= 1000000; \
} \
} while (0)
# define timersub(a, b, result) \
do { \
(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
(result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
if ((result)->tv_usec < 0) { \
--(result)->tv_sec; \
(result)->tv_usec += 1000000; \
} \
} while (0)
#endif /* BSD */
그런데 struct timeval 을 그대로 이용할 때는 불편할 때가 있다.
예를 들어 sec을 일부와 usec의 일부만을 출력하거나
다른 일반 int type으로 저장한 시간과 비교할 때가 그럴 수 있을 것이다.
(어디까지나 선택사항이지만) 이때는 struct timeval 을 long long 으로 변환해서 저장하는 것이 편하다.
아래와 같이 long long time 에 저장하는 것이다.
time = tv.tv_sec * 1000000LL + tv.tv_usec;
참고적으로 혹시 전환 과정에서 data 손실을 우려할 수 있으나 그렇지 않다.
long long type이 보통 8byte 이고, struct timeval의 tv_sec 과 tv_usec 이 각각 4byte 인데,
실제로는 tv_usec의 값은 최대 10^6 - 1 로서, 이는 2진수 값으로 20bit 이하이다.
따라서 20bit 인 2.5byte를 shift 하더라도 데이터 손실이 없는 것이다.
아래는 관련해서 테스트한 소스 코드이며,
struct timeval : 1270047284.534099
long long : 1270047284534099
실행결과 바로 위와 같이 두 값이 같음을 알 수 있다.
#include <stdio.h>
#include <sys/time.h>
int main(int argc, char *argv[])
{
struct timeval tv;
long long time;
if (gettimeofday(&tv, NULL)) fprintf(stderr, "%s error at %d\n", __FUNCTION__, __LINE__);
time = tv.tv_sec * 1000000LL + tv.tv_usec;
printf("struct timeval : %d.%-6d\n", (int)tv.tv_sec, (int)tv.tv_usec);
printf("long long : %lld\n", time);
return 0;
}
'Lang, Tool, Env' 카테고리의 다른 글
Ubuntu /home 옮기기 (0) | 2012.08.04 |
---|---|
struct 내 flag용으로 쓸 1bit 크기 변수 사용하기 (0) | 2010.05.09 |
IEEE Floating-Point Format (1) | 2009.09.13 |
chroot (0) | 2008.04.06 |
임베디드 기초 교육 정리 (0) | 2007.08.26 |