C 언의 localtime() 함수에 대해서
다름이 아니라 localtime() 사용시의 주의 사항에 대해서 나름대로 분석을 해 보앗는데..
잘 맞는 지.. 틀린부분이나 좀더 개념적인 부분에 설명이 필요한 부분에 고수님들의 조언을 부탁드립니다. ^^
자세한 원형은 이것과 유사하리라 생각합니다.
struct tm* localtime(long *)
long 타입 시간값의 포인터를 인자로 받아
struct tm 구조체 포인터를 반환해 주는 것으로 알고 있는데요.(맞나?? ^^;;)
제가 사용하다가 발견한 문제점은..
localtime() 함수를 사용후 반환 받는 (struct tm *) 이것은 안전성이 보장 되지 않는 것이지 않는 가 입니다.
localtime()에서 처리 하는 원형을 알고 싶기는 한데..
일단 생각해 보면 localtime() 함수 안에서 (struct tm)를 선언할테고 그안에 연산을 통해 각 구조체 값에
년, 월, 일, 시, 분... 등등 대입 후 (struct tm *)를 반환할꺼 라고 생각합니다.
함수를 떠나면 (struct tm) 변수는 사라지는게 원칙이고 그 포인터를 반환해줬기 때문에
함수의 반환을 받은 자는 실효성 없는 구조체를 사용한다고 생각합니다..
때문에 다른 곳에서 어떤 메모리 처리를 하게 되면 localtime() 안에서 만든 (struct tm) 위치를 덮어서
다른값으로 변경되지 않는가가 질문의 요지 입니다.
물론 현재 이런 문제가 발생했는데..
그 예는 다음과 같습니다.
--------------------------------------------------------------
long lCurTime = 0;
struct tm *pstCurTime;
char temp[20];
lCurTime = time((time_t*)NULL);
/* 1시간 전 값으로 */
lCurTime = lCurTime - 3600;
pstCurTime = localtime(&lCurTime);
/* printf와 유사하지만 time를 찍어주는 log 함수 : 내부적으로 time, localtime 사용 */
/* 2006-07-12 09:50:31 (Hourly)Before Time[324234234] <-- 위와 같이 시간 출력 */
Log(LOG_DEBUG, "(Hourly)Before Time[%ld]\n", lCurTime);
strcat((char *)sqlCmd.arr, " WHERE collectingdate = to_char(to_date('");
memset(temp, 0x00, sizeof(char) * 20);
sprintf(temp, "%d-%d-%d", pstCurTime->tm_year+1900, pstCurTime->tm_mon+1, pstCurTime->tm_mday);
----------------------------------------------------------------
예를 들어 위와 같이 사용하면
제일 마지막 라인에 사용되는 pstCurTime값은 - 3600 된 값이 아닌 Log() 함수에서 현재시간을 찍은
그 값이 나온다는 말입니다.
(메모리 번지가 뒤집혀 지기 때문에 시스템 마다 다른값이 나올수도 있겠지요??)
때문에 해결책으로
------------------------------------------------------------------------
struct tm stTempTime;
pstCurTime = localtime(&lCurTime);
memcpy(&stTempTime, pstCurTime, sizeof(struct tm));
------------------------------------------------------------------------
이와 같이 복사 해서 해결했습니다.
반환 받은 (struct tm *)을 바로 스칼라 변수에 복사해서 안전하게 만들고
이후에 사용은 스칼라 변수만 사용했습니다.
이렇게 하니 Log() 함수에서 내부적으로 사용되는 time(), localtime()과는 충돌이 발생하지 않더군요..
어찌 분석이 잘 맞는지는 모르겠지만.. 좀더 구체적인 설명이나.. 근거 자료가 있으신분은 부탁드립니다
그럼 다들 즐프 하세요 ^^
struct tm 변수 하나를 C
struct tm 변수 하나를 C 라이브러리 어딘가에 저장해 놓고 같은 포인터만 리턴하기 때문이겠죠.
사실 위의 예보다 더 큰 문제가 되는 게 thread safe하지 않다는 점인데 (어떤 플랫폼의 경우에는 thread specific storage를 사용하기 때문에 스레드에도 안전하긴 하지만), 그 경우 localtime_r()을 쓰면 됩니다.
감사합니다.
localtime_r()
struct tm * localtime_r (const time_t *time, struct tm *resultp)
이런것이 잇었군요.. 검색을 못한 것이 결국 여러번 꼬여서 해결을 하고 있었네요 ^^;;
감사 드려요.. 좋은 것 하나 배웠습니다 ^^
struct tm
는 간단하게
로 하셔도 돼요.
아참, 그리고 localtime()의 인자는 long*이 아니고 time_t*입니다.
typedef long time_t 로 되어 있다면 그게 그거이긴 하지만
그렇지 않을 수도 있으니까...
댓글 달기