Respuestas:
El artículo del 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
time_t
tipo de datos es un tipo de datos en la biblioteca ISO C definida para almacenar valores de tiempo del sistema. Dichos valores se devuelven de latime()
función de biblioteca 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 codificación en particular. Tampoco se especifican los significados de las operaciones aritméticas aplicadas a los valores de tiempo.Los sistemas compatibles con Unix y POSIX implementan el
time_t
tipo comosigned integer
(generalmente de 32 o 64 bits de ancho) que representa el número de segundos desde el inicio de la época de Unix : medianoche UTC del 1 de enero de 1970 (sin contar los segundos bisiestos). Algunos sistemas manejan correctamente los valores de tiempo negativos, mientras que otros no. Los sistemas que utilizan un tipo de 32 bitstime_t
son susceptibles al problema del año 2038 .
time_t
puede suceder el uso de la estructura de datos en el disco. Sin embargo, dado que los sistemas de archivos a menudo son leídos por otros sistemas operativos, sería una tontería definir el sistema de archivos basado en tales tipos dependientes de la implementación. Por ejemplo, el mismo sistema de archivos podría usarse tanto en sistemas de 32 bits como en sistemas de 64 bits, y time_t
podría cambiar el tamaño. Por lo tanto, los sistemas de archivos deben definirse de manera más exacta ("entero de 32 bits con signo que proporcione el número de segundos desde el comienzo de 1970, en UTC") de la misma manera time_t
.
time.h
contenidos. Ese artículo enlaza con cppreference.com pero el contenido citado no se encuentra en ninguna parte ...
time_t
está firmado es incorrecto. pubs.opengroup.org/onlinepubs/9699919799/basedefs/… dicta que varias cosas deben ser un "tipo entero con signo" o "tipo entero sin signo", pero de time_t
eso dice simplemente que "será un tipo entero" . Una implementación puede hacer que time_t
no esté firmada y seguir siendo compatible con POSIX.
[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;
Se define a $INCDIR/bits/types.h
través de:
# 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
typedef __int32_t __time_t;
y typedef __time_t time_t;
en 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
. Sus resultados se establecen explícitamente así en Linux (al menos en 2.6.32-5-xen-amd64 de Debian).
__time_t
y no time_t
encontrar el tipo subyacente de time_t
? ¿Omitiendo un paso?
typedef __time_t time_t;
, el examen del código circundante también es necesario para asegurar que typedef se haya utilizado de hecho y no solo una parte de una compilación condicional. typedef long time_t;
Puede haber sido encontrado también.
Normas
William Brendel citó Wikipedia, pero prefiero que salga 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 (descrito en 7.17) clock_t y time_t que son tipos aritméticos capaces de representar 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 principales son:
typedef long int __time_t;
typedef __time_t time_t;
Desglose de comandos con algunas citas de man gcc
:
-E
: "Deténgase después de la etapa de preprocesamiento; no ejecute el compilador correctamente".-xc
: Especifique el lenguaje C, ya que la entrada proviene de stdin que no tiene extensión de archivo.-include file
: "Procesar archivo como si" #include "archivo" "apareciera como la primera línea del archivo fuente primario".-
: entrada de stdingcc -E -xc -include time.h /dev/null | grep time_t
La respuesta es definitivamente específica de la implementación. Para conocer definitivamente su plataforma / compilador, simplemente 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 deben ir más allá de 2038 , entonces tiene 25 años para migrar su código.
Sus datos estarán bien si almacena sus 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, léalo de la misma manera (fread, fscanf, etc. en un int), y tendrá su tiempo de compensación de época. Una solución similar existe en .Net. Paso sin problemas números de época de 64 bits entre sistemas Win y Linux (a través de un canal de comunicaciones). Eso trae problemas de orden de bytes, pero ese es otro tema.
Para responder a la consulta de paxdiablo, diría que imprimió "19100" porque el programa se escribió 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 printf
declaración imprime la cadena fija "Año es: 19" seguida de una cadena con relleno de cero con los "años desde 1900" (definición detm->tm_year
). En 2000, ese valor es 100, obviamente. "%02d"
rellena con dos ceros pero no se trunca si tiene 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 ese pensamiento?
%zu
especificador de formato para formatear size_t
valores (tal como se obtiene sizeof
), ya que no están firmados ( u
) y tienen una longitud size_t ( z
) ·
printf ("sizeof time_t is: %d\n", (int) sizeof(time_t));
y evite el z
problema.
En Visual Studio 2008, el valor predeterminado es a __int64
menos que usted defina _USE_32BIT_TIME_T
. Es mejor fingir que no sabe cómo se define, ya que puede (y cambiará) de plataforma en plataforma.
time_t
es de tipo long int
en máquinas de 64 bits, de lo contrario eslong long int
.
Puede verificar esto en estos archivos de encabezado:
time.h
: /usr/include
types.h
ytypesizes.h
:/usr/include/x86_64-linux-gnu/bits
(Las siguientes declaraciones no son una tras otra. Se pueden encontrar en el archivo de encabezado de respuesta usando Ctrl + f search).
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;
long int
todas partes. Ver stackoverflow.com/questions/384502/…
Por lo general, encontrará estos typedefs subyacentes específicos de implementación para gcc en el directorio de encabezado bits
o asm
. Para mí lo es /usr/include/x86_64-linux-gnu/bits/types.h
.
Puede simplemente grep, o utilizar una invocación de preprocesador como la sugerida por Quassnoi para ver qué encabezado específico.
¿En qué consiste finalmente un time_t typedef?
El código robusto no le importa cuál es el tipo.
C especies time_t
para ser un tipo real como double, long long, int64_t, int
, etc.
Incluso podría ser unsigned
como los valores de retorno de muchas funciones de tiempo que indican que el error no lo es -1
, pero(time_t)(-1)
- Esta opción de implementación es poco común.
El punto es que la "necesidad de saber" el tipo es rara. El código debe estar escrito para evitar la necesidad.
Sin embargo, se produce una "necesidad de saber" común cuando el código quiere imprimir la materia prima time_t
. La conversión al tipo entero más amplio acomodará los casos más modernos.
time_t now = 0;
time(&now);
printf("%jd", (intmax_t) now);
// or
printf("%lld", (long long) now);
Transmitir a double
o long double
funcionará también, pero podría proporcionar una salida decimal inexacta
printf("%.16e", (double) now);
double difftime(time_t time1, time_t time0)
un enfoque de resta uniforme.
time_t
es solo typedef
para 8 bytes ( long long/__int64
) que todos los compiladores y sistemas operativos entienden. En el long int
pasado , solía ser solo para (4 bytes) pero no ahora. Si nos fijamos en la time_t
en la crtdefs.h
que se encuentra tanto en implementaciones pero el sistema operativo va a utilizar long long
.
long int
.