¿Qué es en definitiva un time_t typedef to?

Busqué en la caja de Linux y vi que era typedef para

typedef __time_t time_t; 

Pero no pude encontrar la definición de __time_t.

El artículo de artículo time_t Wikipedia arroja algo de luz sobre esto. La conclusión es que el tipo de time_t no está garantizado en la especificación C.

El tipo de datos time_t es un tipo de datos en la biblioteca ISO C definida para almacenar valores de tiempo del sistema. Dichos valores se devuelven desde la función de biblioteca time() estándar. Este tipo es un typedef definido en el encabezado estándar. ISO C define time_t como un tipo aritmético, pero no especifica ningún tipo , rango, resolución o encoding particular para él. También no especificados son los significados de las operaciones aritméticas aplicadas a los valores de tiempo.

Los sistemas Unix y POSIX implementan el tipo time_t como un signed integer (típicamente 32 o 64 bits de ancho) que representa el número de segundos desde el inicio de la época Unix : medianoche UTC del 1 de enero de 1970 (sin contar los segundos intercalares). Algunos sistemas manejan correctamente los valores de tiempo negativos, mientras que otros no. Los sistemas que usan un tipo time_t 32 bits son susceptibles al problema del año 2038 .

[root]# cat time.c

 #include  

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

typedef long int __time_t;

Se define en $INCDIR/bits/types.h mediante:

 # 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 

Estándares

William Brendel citó Wikipedia, pero lo prefiero de la boca del caballo.

El borrador estándar C99 N1256 7.23.1 / 3 “Componentes del tiempo” dice:

Los tipos declarados son size_t (descritos en 7.17) clock_t y time_t, que son tipos aritméticos capaces de representar los tiempos

y 6.2.5 / 18 “Tipos” dice:

Los tipos enteros y flotantes se denominan colectivamente tipos aritméticos.

POSIX 7 sys_types.h dice:

[CX] time_t será un tipo entero.

donde [CX] se define como :

[CX] Extensión al estándar ISO C.

Es una extensión porque ofrece una garantía más sólida: los puntos flotantes están fuera.

gcc one-liner

No es necesario crear un archivo como lo menciona Quassnoi :

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

En Ubuntu 15.10 GCC 5.2 las dos líneas superiores son:

 typedef long int __time_t; typedef __time_t time_t; 

La respuesta es definitivamente específica de la implementación. Para descubrir definitivamente su plataforma / comstackdor, solo agregue esta salida en algún lugar de su código:

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

Si la respuesta es 4 (32 bits) y sus datos van más allá de 2038 , entonces tiene 25 años para migrar su código.

Tus datos estarán bien si almacenas tus datos como una cadena, incluso si es algo simple como:

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

Luego solo léalo de la misma manera (fread, fscanf, etc. en un int), y tiene su tiempo de offset de época. Existe una solución similar en .Net. Paso sin problemas los números epoch de 64 bits entre los sistemas Win y Linux (a través de un canal de comunicaciones). Eso trae a colación los problemas de orden de bytes, pero ese es otro tema.

Para responder a la consulta de paxdiablo, diría que imprimió “19100” porque el progtwig fue escrito de esta manera (y admito que lo hice yo mismo en los años 80):

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

La sentencia printf imprime la cadena fija “Año es: 19” seguida de una cadena sin relleno con los “años desde 1900” (definición de tm->tm_year ). En 2000, ese valor es 100, obviamente. "%02d" con dos ceros pero no truncan si tienen más de dos dígitos.

La forma correcta es (cambiar a la última línea solamente):

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

Nueva pregunta: ¿Cuál es la razón de ser de ese pensamiento?

En Visual Studio 2008, su valor predeterminado es un __int64 menos que defina _USE_32BIT_TIME_T . Es mejor simplemente fingir que no sabe cómo se define, ya que puede (y lo hará) cambiar de una plataforma a otra.

time_t es de tipo long int en máquinas de 64 bits, sino que es long long int .

Puede verificar esto en estos archivos de encabezado:

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

(Las declaraciones a continuación no son una después de otra. Se pueden encontrar en el archivo de encabezado resp. Usando Ctrl + f búsqueda.)

1) En time.h

 typedef __time_t time_t; 

2) En types.h

 # define __STD_TYPE typedef __STD_TYPE __TIME_T_TYPE __time_t; 

3) En 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) De nuevo en 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; 

Es un tipo entero con signo de 32 bits en la mayoría de las plataformas heredadas. Sin embargo, eso hace que tu código sufra el error del año 2038 . Por lo tanto, las bibliotecas C modernas deberían definirlo como un int firmado de 64 bits, que es seguro durante unos pocos miles de millones de años.

Normalmente encontrará estos typedefs subyacentes específicos de la implementación para gcc en el directorio de cabeceras de bits o asm . Para mí, es /usr/include/x86_64-linux-gnu/bits/types.h .

Puede grep o utilizar una invocación de preprocesador como la sugerida por Quassnoi para ver qué encabezado específico.

time_t es simplemente typedef para 8 bytes ( long long/__int64 ) que todos los comstackdores y sistemas operativos entienden. En los días anteriores, solía ser solo por long int (4 bytes) pero ahora no. Si mira el time_t en crtdefs.h , encontrará ambas implementaciones pero el sistema operativo usará long long .

¿Qué es en definitiva un time_t typedef to?

A un código robusto no le importa el tipo.

C especie time_t para ser un tipo real como double, long long, int64_t, int , etc.

Incluso podría unsigned estar unsigned ya que los valores de retorno de muchas funciones horarias que indican el error no son -1 , sino (time_t)(-1) – Esta opción de implementación es poco común.

El punto es que el tipo de “necesidad de saber” es raro. El código debe escribirse para evitar la necesidad.


Sin embargo, una “necesidad de saber” común ocurre cuando el código quiere imprimir el time_t crudo. La conversión al tipo entero más amplio acomodará la mayoría de los casos modernos.

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

La conversión a double o long double funcionará también, pero podría proporcionar una salida decimal inexacta

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