Programming

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

procodes 2020. 5. 15. 21:07
반응형

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


Linux 상자를 검색하고 다음 typedef를 보았습니다.

typedef __time_t time_t;

그러나 나는 그 __time_t정의를 찾을 수 없었다 .


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 년 문제에 취약합니다 .


[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

표준

윌리엄 브렌델 (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에서 입력

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

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에도 비슷한 해결 방법이 있습니다. Win과 Linux 시스템간에 64 비트 에포크 번호를 전달합니다 (통신 채널을 통해). 바이트 순서 문제가 발생하지만 다른 주제입니다.

To answer paxdiablo's query, I'd say that it printed "19100" because the program was written this way (and I admit I did this myself in the '80's):

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);

The printf statement prints the fixed string "Year is: 19" followed by a zero-padded string with the "years since 1900" (definition of tm->tm_year). In 2000, that value is 100, obviously. "%02d" pads with two zeros but does not truncate if longer than two digits.

The correct way is (change to last line only):

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

New question: What's the rationale for that thinking?


Under Visual Studio 2008, it defaults to an __int64 unless you define _USE_32BIT_TIME_T. You're better off just pretending that you don't know what it's defined as, since it can (and will) change from platform to platform.


time_t is of type long int on 64 bit machines, else it is long long int.

You could verify this in these header files:

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

(The statements below are not one after another. They could be found in the resp. header file using Ctrl+f search.)

1)In time.h

typedef __time_t time_t;

2)In types.h

# define __STD_TYPE     typedef  
__STD_TYPE __TIME_T_TYPE __time_t;  

3)In 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) Again in 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;

It's a 32-bit signed integer type on most legacy platforms. However, that causes your code to suffer from the year 2038 bug. So modern C libraries should be defining it to be a signed 64-bit int instead, which is safe for a few billion years.


Typically you will find these underlying implementation-specific typedefs for gcc in the bits or asm header directory. For me, it's /usr/include/x86_64-linux-gnu/bits/types.h.

You can just grep, or use a preprocessor invocation like that suggested by Quassnoi to see which specific header.


What is ultimately a time_t typedef to?

Robust code does not care what the type is.

C species time_t to be a real type like double, long long, int64_t, int, etc.

It even could be unsigned as the return values from many time function indicating error is not -1, but (time_t)(-1) - This implementation choice is uncommon.

The point is that the "need-to-know" the type is rare. Code should be written to avoid the need.


Yet a common "need-to-know" occurs when code wants to print the raw time_t. Casting to the widest integer type will accommodate most modern cases.

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

Casting to a double or long double will work too, yet could provide inexact decimal output

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

time_t is just typedef for 8 bytes (long long/__int64) which all compilers and OS's understand. Back in the days, it used to be just for long int (4 bytes) but not now. If you look at the time_t in crtdefs.h you will find both implementations but the OS will use long long.

참고URL : https://stackoverflow.com/questions/471248/what-is-time-t-ultimately-a-typedef-to

반응형