El artículo del artículo time_t Wikipedia arroja algo de luz sobre esto. La conclusión es que el tipo de time_tno está garantizado en la especificación C.
El time_ttipo 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 la time()
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_ttipo como signed
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 bits time_tson susceptibles al problema del año 2038 .
Sin embargo, tenga en cuenta que los valores de time_t generalmente solo se almacenan en la memoria, no en el disco. En cambio, time_t se convierte en texto u otro formato portátil para el almacenamiento persistente. Eso hace que el problema Y2038 no sea realmente un problema.
11
@Heath: en un sistema específico, donde las mismas personas crean el sistema operativo y la biblioteca C, time_tpuede 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_tpodrí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.
1
Como nota: el artículo vinculado de Wikipedia se ha eliminado y ahora se redirige a la lista de time.hcontenidos. Ese artículo enlaza con cppreference.com pero el contenido citado no se encuentra en ninguna parte ...
Michał Górny
3
@ MichałGórny: Corregido, siempre y cuando no se eliminen los artículos, siempre puedes echar un vistazo al historial para encontrar la versión correcta.
Zeta
44
-1; El reclamo citado de Wikipedia que POSIX garantiza que time_testá 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_teso dice simplemente que "será un tipo entero" . Una implementación puede hacer que time_tno esté firmada y seguir siendo compatible con POSIX.
Veo ambos 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).
¿Por qué buscar __time_ty no time_tencontrar el tipo subyacente de time_t? ¿Omitiendo un paso?
chux - Restablece a Mónica el
@ chux-ReinstateMonica - El OP dijo que había encontrado el typedef de time_t a __time_t. Esta respuesta solo aborda la pregunta de qué __time_t se define. Pero estoy de acuerdo en que para un caso genérico (donde time_t puede no estar definido como __time_t), primero necesitaría grep por time_t, y luego posiblemente grep nuevamente por lo que eso devuelve
Michael Firth
@MichaelFirth Bastante justo. Recuerdo mi preocupación porque, aunque OP encontró 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.
chux - Restablece a Mónica
30
Normas
William Brendel citó Wikipedia, pero prefiero que salga de la boca del caballo.
No hay necesidad de que la tubería se gcc -E -xc -include time.h /dev/null | grep time_t
repita
12
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 printfdeclaració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?
Probablemente debería usar el %zuespecificador de formato para formatear size_tvalores (tal como se obtiene sizeof), ya que no están firmados ( u) y tienen una longitud size_t ( z) ·
Adrian Günter
... o use printf ("sizeof time_t is: %d\n", (int) sizeof(time_t));y evite el zproblema.
chux - Restablece a Mónica el
6
En Visual Studio 2008, el valor predeterminado es a __int64menos 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.
Eso generalmente funciona, pero si su programa está destinado a realizar un seguimiento de las cosas que sucederán dentro de 30 años, es bastante importante que no tenga un time_t de 32 bits firmado.
Rob Kennedy el
44
@ Rob, bah, ¡déjalo! Comenzaremos a correr como pollos sin cabeza en 2036, lo mismo que hicimos para Y2K. Algunos de nosotros va a hacer una bucketload de dinero de ser consultores Y2k38, Leonard Nimoy sacará otro libro hilarante sobre la forma en que todos deberíamos ir y esconderse en el bosque ...
paxdiablo
1
... y todo se desvanecerá, el público se preguntará por qué tanto alboroto. Incluso puedo salir de la jubilación para ganar dinero para la herencia de los niños :-).
paxdiablo
2
Por cierto, sólo encontramos una bichos Y2K y que era una página web que aparece la fecha del 1 de enero de 19100. El ejercicio para el lector por qué ...
paxdiablo
9
Si el evento que sucederá en 30 años es "caducar esta copia de seguridad", entonces podría estar en problemas AHORA, no en 2038. Agregue 30 años al actual time_t de 32 bits y obtendrá una fecha en el pasado. Su programa busca eventos para procesar, encuentra uno que está atrasado (¡en 100 años!) Y lo ejecuta. Vaya, no más copias de seguridad.
Rob Kennedy el
5
time_tes de tipo long inten máquinas de 64 bits, de lo contrario eslong long int .
Puede verificar esto en estos archivos de encabezado:
Es un tipo entero con signo de 32 bits en la mayoría de las plataformas heredadas. Sin embargo, eso hace que su código sufra el error del año 2038 . Por lo tanto, las bibliotecas C modernas deberían definirlo como un int de 64 bits con signo, lo que es seguro durante unos miles de millones de años.
Por lo general, encontrará estos typedefs subyacentes específicos de implementación para gcc en el directorio de encabezado bitso asm. Para mí lo es /usr/include/x86_64-linux-gnu/bits/types.h.
C especies time_tpara ser un tipo real como double, long long, int64_t, int, etc.
Incluso podría ser unsignedcomo 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",(longlong) now);
Transmitir a doubleo long doublefuncionará también, pero podría proporcionar una salida decimal inexacta
Necesito saber la situación porque necesito transferir tiempo de un sistema ARM a un sistema AMD64. time_t tiene 32 bits en el brazo y 64 bits en el servidor. si traduzco el tiempo a un formato y envío una cadena, es ineficiente y lento. Por lo tanto, es mucho mejor enviar todo el time_t y ordenarlo en el servidor. Sin embargo, necesito entender el tipo un poco más porque no quiero que el número se altere por la diferencia de endianness entre los sistemas, así que necesito usar htonl ... pero primero, sobre la base de una necesidad de saber, quiero para descubrir el tipo subyacente;)
Owl
Otro caso de "necesidad de saber", al menos para firmado frente a no firmado, es si debe tener cuidado al restar tiempos. Si simplemente "resta e imprime el resultado", posiblemente obtendrá lo que espera en un sistema con un time_t con signo, pero no con un time_t sin signo.
Michael Firth
@MichaelFirth Existen casos para time_t con signo entero y time_t sin signo donde la resta sin procesar dará como resultado resultados inesperados. C proporciona double difftime(time_t time1, time_t time0)un enfoque de resta uniforme.
chux - Restablece a Mónica
-3
time_tes solo typedefpara 8 bytes ( long long/__int64) que todos los compiladores y sistemas operativos entienden. En el long intpasado , solía ser solo para (4 bytes) pero no ahora. Si nos fijamos en la time_ten la crtdefs.hque se encuentra tanto en implementaciones pero el sistema operativo va a utilizar long long.
todos los compiladores y sistemas operativos? No. En mi sistema Linux, el compilador toma la implementación firmada de 4 bytes.
Vincent
En los sistemas Zynq 7010, time_t es 4bytes.
Búho
1
En los sistemas integrados, trabajo en time_t casi siempre es de 32 bits o 4 bytes. El estándar establece específicamente que es específico de la implementación lo que hace que esta respuesta sea incorrecta.
long int
.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.fuente
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, ytime_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 maneratime_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 detime_t
eso dice simplemente que "será un tipo entero" . Una implementación puede hacer quetime_t
no esté firmada y seguir siendo compatible con POSIX.[root]# cat time.c
[root]# gcc -E time.c | grep __time_t
typedef long int __time_t;
Se define a
$INCDIR/bits/types.h
través de:fuente
typedef __int32_t __time_t;
ytypedef __time_t time_t;
en aFreeBSD 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 notime_t
encontrar el tipo subyacente detime_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:
y 6.2.5 / 18 "Tipos" dice:
POSIX 7 sys_types.h dice:
donde
[CX]
se define como :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 :
En Ubuntu 15.10 GCC 5.2, las dos líneas principales son:
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 stdinfuente
gcc -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:
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:
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):
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):
Nueva pregunta: ¿Cuál es la razón de ese pensamiento?
fuente
%zu
especificador de formato para formatearsize_t
valores (tal como se obtienesizeof
), 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 elz
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.fuente
time_t
es de tipolong 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
2) en
types.h
3 en
typesizes.h
4) De nuevo en
types.h
fuente
long int
todas partes. Ver stackoverflow.com/questions/384502/…Es un tipo entero con signo de 32 bits en la mayoría de las plataformas heredadas. Sin embargo, eso hace que su código sufra el error del año 2038 . Por lo tanto, las bibliotecas C modernas deberían definirlo como un int de 64 bits con signo, lo que es seguro durante unos miles de millones de años.
fuente
Por lo general, encontrará estos typedefs subyacentes específicos de implementación para gcc en el directorio de encabezado
bits
oasm
. 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.
fuente
El código robusto no le importa cuál es el tipo.
C especies
time_t
para ser un tipo real comodouble, 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.Transmitir a
double
olong double
funcionará también, pero podría proporcionar una salida decimal inexactafuente
double difftime(time_t time1, time_t time0)
un enfoque de resta uniforme.time_t
es solotypedef
para 8 bytes (long long/__int64
) que todos los compiladores y sistemas operativos entienden. En ellong int
pasado , solía ser solo para (4 bytes) pero no ahora. Si nos fijamos en latime_t
en lacrtdefs.h
que se encuentra tanto en implementaciones pero el sistema operativo va a utilizarlong long
.fuente