time_t는 궁극적으로 typedef 무엇입니까?


답변:


175

time_t 위키 백과 문서의 문서에서는이에 대한 몇 가지 빛이 나고. 결론 time_t은 C 사양에서 유형이 보장되지 않는다는 것입니다.

time_t데이터 유형이 시스템 타임 값을 저장하기 위해 정의 된 ISO C 라이브러리의 데이터 형식이다. 이러한 값은 표준 time() 라이브러리 함수 에서 반환됩니다 . 이 유형은 표준 헤더에 정의 된 typedef입니다. ISO C는 time_t를 산술 유형으로 정의하지만 특정 유형 , 범위, 해상도 또는 인코딩을 지정하지는 않습니다 . 시간 값에 적용되는 산술 연산의 의미도 지정되어 있지 않습니다.

유닉스 및 POSIX 호환 시스템 은 유닉스 시대가 시작된 이래 초 수를 나타내는 (일반적으로 32 또는 64 비트 폭) time_t유형을 구현합니다 signed integer( 1970 년 1 월 1 일 자정 UTC (윤초 계산 제외)). 일부 시스템은 음의 시간 값을 올바르게 처리하지만 다른 시스템은 그렇지 않습니다. 32 비트 time_t유형을 사용하는 시스템 은 2038 년 문제에 취약합니다 .


6
그러나 time_t 값은 일반적으로 디스크가 아닌 메모리에만 저장됩니다. 대신, time_t는 영구 저장을 위해 텍스트 또는 다른 휴대용 형식으로 변환됩니다. 따라서 Y2038 문제는 실제로 문제가되지 않습니다.

11
@Heath : 특정 시스템에서 동일한 사용자가 운영 체제 및 C 라이브러리를 작성 time_t하는 경우 온 디스크 데이터 구조를 사용하여 발생할 수 있습니다. 그러나 파일 시스템은 종종 다른 운영 체제에서 읽으므로 구현에 따라 다른 유형에 따라 파일 시스템을 정의하는 것은 어리석은 일입니다. 예를 들어, 동일한 파일 시스템이 32 비트 및 64 비트 시스템 모두에서 사용될 수 있으며 time_t크기가 변경 될 수 있습니다. 따라서 파일 시스템은 다음과 같이보다 정확하게 정의해야합니다 ( "1970 년 시작 이후 32 초 부호있는 정수 (UTC)") time_t.

1
참고 : 링크 된 Wikipedia 기사가 제거되었으며 이제 time.h컨텐츠 목록으로 리디렉션됩니다 . 해당 기사의 링크 cppreference.com하지만 인용 된 콘텐츠는 아무데도 ... 발견 할 수있다
마이클 Górny

3
@ MichałGórny : 기사가 삭제되지 않는 한 항상 정확한 버전을 찾기 위해 기록을 볼 수 있습니다.
Zeta

4
-1; POSIX time_t가 서명 한 것을 보증한다고 Wikipedia에서 인용 한 주장 이 잘못되었습니다. pubs.opengroup.org/onlinepubs/9699919799/basedefs/… 는 다양한 것들이 "부호있는 정수형"또는 "부호없는 정수형"이어야 한다고 지시하지만, time_t단지 "정수형이어야한다" 고 말합니다 . 구현은 time_t서명되지 않고 POSIX 호환이 될 수 있습니다.
Mark Amery

112

[root]# cat time.c

#include <time.h>

int main(int argc, char** argv)
{
        time_t test;
        return 0;
}

[root]# gcc -E time.c | grep __time_t

typedef long int __time_t;

다음을 $INCDIR/bits/types.h통해 정의됩니다 .

# 131 "/usr/include/bits/types.h" 3 4
# 1 "/usr/include/bits/typesizes.h" 1 3 4
# 132 "/usr/include/bits/types.h" 2 3 4

1
둘 다 볼 typedef __int32_t __time_t;typedef __time_t time_t;A의 FreeBSD freebsd-test 8.2-RELEASE-p2 FreeBSD 8.2-RELEASE-p2 #8: Sun Aug 7 18:23:48 UTC 2011 root@freebsd-test:/usr/obj/usr/src/sys/MYXEN i386. 결과는 Linux에서 명시 적으로 설정됩니다 (Debian의 2.6.32-5-xen-amd64 이상).
ssice

1
@Viet은 파일을 만들지 않고 단일 라이너로도 가능합니다. stackoverflow.com/a/36096104/895245
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
왜 grep으로 __time_t하지 time_t의 기본 유형을 찾기 위해 time_t? 단계를 생략?
chux-복원 Monica Monica

@ chux-ReinstateMonica-OP는 time_t에서 __time_t까지 typedef를 찾았다 고 말했다. 이 답변은 __time_t가 정의 된 질문을 해결하는 것입니다. 그러나 일반적인 경우 (time_t를 __time_t로 입력 할 수없는 경우)에는 time_t를 먼저 grep 한 다음 반환되는 내용에 대해 다시 grep해야한다는 데 동의합니다.
Michael Firth

@MichaelFirth 박람회 충분합니다. OP가 발견 되었더라도 typedef __time_t time_t;typedef가 실제로 사용되고 조건부 컴파일의 일부가 아니라는 것을 보장하기 위해 주변 코드의 검사도 필요하다고 생각합니다. typedef long time_t;발견되었을 수도 있습니다.
chux-복원 Monica Monica

30

표준

윌리엄 브렌델 (William Brendel) 은 Wikipedia를 인용했지만, 나는 말의 입에서 그것을 선호합니다.

C99 N1256 표준 초안 7.23.1 / 3 "시간 요소" 는 다음과 같이 말합니다.

선언 된 타입은 size_t (7.17에서 설명) clock_t와 time_t로 시간을 표현할 수있는 산술 타입입니다.

6.2.5 / 18 "종류"는 말합니다 :

정수 및 부동 유형을 통칭하여 산술 유형이라고합니다.

POSIX 7 sys_types.h 는 다음과 같이 말합니다.

[CX] time_t는 정수 타입이어야한다.

어디는 [CX]되고 정의 :

[CX] ISO C 표준으로의 확장.

부동 소수점이 더 강력하다는 것을 보증하기 때문에 확장입니다.

gcc 원 라이너

Quassnoi가 언급 한대로 파일을 만들 필요가 없습니다 .

echo | gcc -E -xc -include 'time.h' - | grep time_t

Ubuntu 15.10 GCC 5.2에서 두 줄은 다음과 같습니다.

typedef long int __time_t;
typedef __time_t time_t;

따옴표로 묶은 명령 분석 man gcc:

  • -E: "전처리 단계 후 중지하고 컴파일러를 올바르게 실행하지 마십시오."
  • -xc: 파일 확장자가없는 stdin에서 입력이 이루어 지므로 C 언어를 지정하십시오.
  • -include file: ""#include "file" "이 기본 소스 파일의 첫 번째 줄로 나타난 것처럼 파일을 처리하십시오."
  • -: stdin에서 입력

1
에코에서 파이프가 필요하지 않습니다.gcc -E -xc -include time.h /dev/null | grep time_t
rvighne

12

답은 구현에 따라 다릅니다. 플랫폼 / 컴파일러에 대해 확실하게 알아 보려면 코드의 어딘가에이 출력을 추가하십시오.

printf ("sizeof time_t is: %d\n", sizeof(time_t));

답이 4 (32 비트)이고 데이터가 2038을 넘어서는 경우 25 년 동안 코드를 마이그레이션해야합니다.

데이터가 다음과 같은 간단한 경우에도 데이터를 문자열로 저장하면 데이터가 좋습니다.

FILE *stream = [stream file pointer that you've opened correctly];
fprintf (stream, "%d\n", (int)time_t);

그런 다음 같은 방식으로 다시 읽습니다 (fread, fscanf 등을 정수로), epoch 오프셋 시간이 있습니다. .Net에도 비슷한 해결 방법이 있습니다. Windows와 Linux 시스템간에 64 비트 에포크 번호를 전달합니다 (통신 채널을 통해). 바이트 순서 문제가 발생하지만 다른 주제입니다.

paxdiablo의 질문에 답하기 위해 프로그램이 이런 식으로 작성 되었기 때문에 "19100"이 인쇄되었다고 말하고 싶습니다.

time_t now;
struct tm local_date_time;
now = time(NULL);
// convert, then copy internal object to our object
memcpy (&local_date_time, localtime(&now), sizeof(local_date_time));
printf ("Year is: 19%02d\n", local_date_time.tm_year);

그만큼 printf 명령문은 고정 문자열 "Year is : 19"와 "1900 이후 연도"(정의 tm->tm_year) 로 채워진 0으로 채워진 문자열을 인쇄합니다 . 2000 년에는 분명히 그 가치가 100입니다. "%02d"두 개의 0으로 채워지지만 두 자리보다 길면 잘리지 않습니다.

올바른 방법은 (마지막 줄로만 변경)입니다.

printf ("Year is: %d\n", local_date_time.tm_year + 1900);

새로운 질문 : 그 사고에 대한 이론적 근거는 무엇입니까?


2
값 을 부호가 없고 ( ) 길이가 size_t ( ) · %zu형식으로 size_t값을 지정 하려면 형식 지정자를 사용해야합니다.sizeofuz
Adrian Günter

또는 문제를 사용 printf ("sizeof time_t is: %d\n", (int) sizeof(time_t));하고 피하십시오 z.
chux-복원 Monica Monica

6

Visual Studio 2008에서는 기본적으로 __int64 를 정의하지 않으면_USE_32BIT_TIME_T . 플랫폼에서 플랫폼으로 변경할 수 있기 때문에 정의 된 내용을 모르는 척하는 것이 좋습니다.


2
일반적으로 작동하지만 프로그램이 30 년 후에 발생할 일을 추적하려는 경우 부호있는 32 비트 time_t가 없는 것이 중요합니다 .
Rob Kennedy

4
@Rob, bah, 그만둬! 우리는 Y2K에서와 마찬가지로 2036 년에 머리없는 닭처럼 뛰어 다니기 시작합니다. 우리 중 일부는 Y2k38 컨설턴트가되어 많은 돈을 벌게 될 것입니다. Leonard Nimoy는 우리 모두가 숲에서 어떻게 숨어서 숨어 야하는지에 대한 또 다른 재미있는 책을 가져올 것입니다.
paxdiablo

1
... 그리고 모든 소란이 터질 것입니다. 대중은 모든 소란이 무엇인지 궁금합니다. 나는 심지어 아이들의 상속을 위해 돈을 벌기 위해 은퇴에서 나올 수도 있습니다 :-).
paxdiablo 2018 년

2
BTW, 우리는 하나 개의 Y2K 버그를 발견 얀 1과 날짜를 나열 웹 페이지이었다 그에게로 독자 19100. 운동 이유는 ...
paxdiablo

9
30 년 내에 발생하는 이벤트가 "이 백업 만료"인 경우 2038 년이 아니라 지금 문제가 발생할 수 있습니다. 오늘의 32 비트 time_t에 30 년을 추가하면 과거 날짜가 표시됩니다. 프로그램은 처리 할 이벤트를 찾고 기한이 지난 (100 년이 지난) 이벤트를 찾아서 실행합니다. 죄송합니다. 더 이상 백업하지 않습니다.
Rob Kennedy

5

time_tlong int64 비트 시스템에서 유형 이며 그렇지 않은 경우입니다 long long int.

다음 헤더 파일에서이를 확인할 수 있습니다.

time.h: /usr/include
types.htypesizes.h:/usr/include/x86_64-linux-gnu/bits

(아래 문장들은 차례 차례가 아닙니다. Ctrl + f 검색을 사용하여 resp. 헤더 파일에서 찾을 수 있습니다.)

1)에서 time.h

typedef __time_t time_t;

2)에서 types.h

# define __STD_TYPE     typedef  
__STD_TYPE __TIME_T_TYPE __time_t;  

3)에서 typesizes.h

#define __TIME_T_TYPE       __SYSCALL_SLONG_TYPE  
#if defined __x86_64__ && defined __ILP32__  
# define __SYSCALL_SLONG_TYPE   __SQUAD_TYPE  
#else
# define __SYSCALL_SLONG_TYPE   __SLONGWORD_TYPE
#endif  

4) 다시 types.h

#define __SLONGWORD_TYPE    long int
#if __WORDSIZE == 32
# define __SQUAD_TYPE       __quad_t
#elif __WORDSIZE == 64
# define __SQUAD_TYPE       long int  

#if __WORDSIZE == 64
typedef long int __quad_t;  
#else
__extension__ typedef long long int __quad_t;

이 파일들은 glibc가 Ubuntu 15.10 BTW에서 제공합니다.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

3
long int어디에나 있지는 않습니다 . 참조 stackoverflow.com/questions/384502/...
ZAN 살쾡이

4

대부분의 레거시 플랫폼에서 32 비트 부호있는 정수 유형입니다. 그러나 코드가 2038 년 버그 로 고통받습니다 . 따라서 현대 C 라이브러리는 대신 부호있는 64 비트 int로 정의해야하며 이는 수십 년 동안 안전합니다.



1

궁극적으로 time_t typedef는 무엇입니까?

강력한 코드는 유형이 무엇인지 신경 쓰지 않습니다.

C 종은 time_t할 수 진짜 형 처럼 double, long long, int64_t, int, 등

심지어 수 unsigned많은 시간 함수의 리턴 값은 오류가없는 표시로 -1하지만,(time_t)(-1) -이 구현 선택은 드물다.

요점은 "알아야 할 필요"유형이 드물다는 것입니다. 필요를 피하기 위해 코드를 작성해야합니다.


그러나 코드가 raw를 인쇄하려고 할 때 일반적인 "알아야 할 필요"가 발생합니다 time_t. 가장 넓은 정수 유형으로 캐스팅하면 대부분의 최신 사례를 수용 할 수 있습니다.

time_t now = 0;
time(&now);
printf("%jd", (intmax_t) now);
// or 
printf("%lld", (long long) now);

에 캐스팅 double하거나 long double작동하지만 정확하게 10 진 출력을 제공 할 수 있음

printf("%.16e", (double) now);

ARM 시스템에서 AMD64 시스템으로 시간을 전송해야하기 때문에 상황을 알아야합니다. time_t는 암에서 32 비트, 서버에서 64 비트입니다. 시간을 형식으로 변환하고 문자열을 보내면 비효율적이며 느립니다. 따라서 전체 time_t를 보내고 서버 쪽에서 정렬하는 것이 훨씬 좋습니다. 그러나 시스템 간 엔디안이 다르기 때문에 숫자가 엉망이되는 것을 원하지 않기 때문에 유형을 조금 더 이해해야합니다. 그래서 htonl을 사용해야합니다 ...하지만 먼저 알아야 할 사항이 있습니다. 기본 유형을 찾으려면;)
Owl

서명 된 대 서명되지 않은 다른 경우에 대해 알아야 할 또 다른 사례는 시간을 뺄 때주의해야하는지 여부입니다. "결과를 빼서 인쇄하기"만하면 서명 된 time_t는 있지만 서명되지 않은 time_t는없는 시스템에서 예상 한 결과를 얻을 수 있습니다.
마이클 퍼스

@MichaelFirth 정수 빼기 time_t 및 부호없는 time_t에 대해 대 / 소문자를 빼면 예기치 않은 결과가 발생합니다. C는 double difftime(time_t time1, time_t time0)균일 한 빼기 방법을 제공합니다 .
chux-복원 Monica Monica

-3

time_t그냥 typedef8 바이트 (에 대한 long long/__int64모든 컴파일러 및 OS의 이해). 옛날에는 long int(4 바이트) 였지만 지금은 아닙니다. time_tin 을 보면 crtdefs.h두 가지 구현을 모두 찾을 수 있지만 OS가 사용 long long합니다.


5
모든 컴파일러와 OS? 내 리눅스 시스템에서 컴파일러는 4 바이트 부호있는 구현을 취합니다.
Vincent

Zynq 7010 시스템에서 time_t는 4 바이트입니다.
올빼미

1
임베디드 시스템에서 time_t 작업은 거의 항상 32 비트 또는 4 바이트입니다. 이 표준은 구체적으로 구현에 따라 다르며,이 답변은 잘못되었습니다.
Cobusve
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.