L' article de Time_t sur Wikipédia apporte un éclairage à ce sujet. L'essentiel est que le type de time_tn'est pas garanti dans la spécification C.
Le time_ttype de données est un type de données dans la bibliothèque ISO C défini pour stocker les valeurs d'heure système. Ces valeurs sont renvoyées par la time()
fonction de bibliothèque standard . Ce type est un typedef défini dans l'en-tête standard. ISO C définit time_t comme un type arithmétique, mais ne spécifie aucun type , plage, résolution ou encodage particulier pour lui. La signification des opérations arithmétiques appliquées aux valeurs temporelles n'est pas non plus spécifiée.
Les systèmes compatibles Unix et POSIX implémentent le time_ttype en tant que signed
integer(généralement de 32 ou 64 bits de large) qui représente le nombre de secondes depuis le début de l'époque Unix : minuit UTC du 1er janvier 1970 (sans compter les secondes intercalaires). Certains systèmes gèrent correctement les valeurs de temps négatives, tandis que d'autres ne le font pas. Les systèmes utilisant un type 32 bits time_tsont sensibles au problème de l' an 2038 .
Notez, cependant, que les valeurs de time_t ne sont généralement stockées qu'en mémoire, pas sur disque. Au lieu de cela, time_t est converti en texte ou en un autre format portable pour un stockage persistant. Cela fait que le problème Y2038 n'est pas vraiment un problème.
11
@Heath: sur un système spécifique, où les mêmes personnes créent le système d'exploitation et la bibliothèque C, l'utilisation time_tdans la structure de données sur disque peut se produire. Cependant, comme les systèmes de fichiers sont souvent lus par d'autres systèmes d'exploitation, il serait idiot de définir le système de fichiers en fonction de ces types dépendants de l'implémentation. Par exemple, le même système de fichiers peut être utilisé à la fois sur des systèmes 32 bits et 64 bits et time_tpeut changer de taille. Ainsi, les systèmes de fichiers doivent être définis plus précisément ("Entier signé 32 bits donnant le nombre de secondes depuis le début de 1970, en UTC") que tout comme time_t.
1
Remarque: l'article Wikipedia lié a été supprimé et il redirige désormais vers la liste des time.hcontenus. Cet article renvoie à cppreference.com mais le contenu cité est introuvable…
Michał Górny
3
@ MichałGórny: Correction, tant que les articles ne sont pas supprimés, vous pouvez toujours consulter l'historique afin de trouver la bonne version.
Zeta
4
-1; l'affirmation citée sur Wikipedia selon laquelle POSIX garantit la time_tsignature est incorrecte. pubs.opengroup.org/onlinepubs/9699919799/basedefs/… dicte que diverses choses doivent être un "type entier signé" ou "type entier non signé", mais time_tcela dit simplement qu'il "doit être un type entier" . Une implémentation peut être time_tnon signée et toujours conforme à POSIX.
Je vois les deux typedef __int32_t __time_t;et typedef __time_t time_t;dans un 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. Vos résultats sont explicitement définis comme cela sous Linux (au moins sur 2.6.32-5-xen-amd64 de Debian).
Pourquoi chercher __time_tet ne time_tpas trouver le type sous-jacent de time_t? Omettre une étape?
chux
@ chux-ReinstateMonica - L'OP a dit qu'il avait trouvé le typedef de time_t à __time_t. Cette réponse ne fait que répondre à la question posée sur la définition de __time_t. Mais je suis d'accord que pour un cas générique (où time_t ne peut pas être tapé à __time_t), vous devrez d'abord chercher gre time_t, puis éventuellement encore grep pour ce que cela renvoie
Michael Firth
@MichaelFirth Assez juste. Je me souviens de ma préoccupation car même si OP l'a trouvé typedef __time_t time_t;, l'examen du code environnant est également nécessaire pour s'assurer que typedef a bien été utilisé et pas seulement une partie d'une compilation conditionnelle. typedef long time_t;peut avoir été trouvé aussi.
chux
30
Normes
William Brendel a cité Wikipedia, mais je le préfère de la bouche du cheval.
Pas besoin non plus de la pipe d'echo:gcc -E -xc -include time.h /dev/null | grep time_t
rvighne
12
La réponse est définitivement spécifique à l'implémentation. Pour connaître définitivement votre plateforme / compilateur, ajoutez simplement cette sortie quelque part dans votre code:
printf ("sizeof time_t is: %d\n",sizeof(time_t));
Si la réponse est 4 (32 bits) et que vos données doivent dépasser 2038 , vous disposez de 25 ans pour migrer votre code.
Vos données seront correctes si vous stockez vos données sous forme de chaîne, même si c'est quelque chose de simple comme:
FILE*stream =[stream file pointer that you've opened correctly];
fprintf (stream,"%d\n",(int)time_t);
Ensuite, lisez-le de la même manière (fread, fscanf, etc. dans un int), et vous avez votre temps de décalage d'époque. Une solution de contournement similaire existe dans .Net. Je passe des numéros d'époque 64 bits entre les systèmes Win et Linux sans problème (sur un canal de communication). Cela soulève des problèmes d'ordre des octets, mais c'est un autre sujet.
Pour répondre à la requête de paxdiablo, je dirais qu'il a imprimé "19100" parce que le programme a été écrit de cette façon (et j'avoue que je l'ai fait moi-même dans les années 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);
L' printfinstruction imprime la chaîne fixe "Year is: 19" suivie d'une chaîne à zéro avec les "années depuis 1900" (définition de tm->tm_year). En 2000, cette valeur est 100, évidemment. "%02d"tampons avec deux zéros mais ne tronquent pas si plus de deux chiffres.
La façon correcte est (passer à la dernière ligne uniquement):
printf ("Year is: %d\n", local_date_time.tm_year +1900);
Nouvelle question: quelle est la justification de cette réflexion?
Vous devriez probablement utiliser le %zuspécificateur de format pour formater les size_tvaleurs (telles que fournies par sizeof), car elles sont non signées ( u) et de longueur size_t ( z) ·
Adrian Günter
... ou utilisez printf ("sizeof time_t is: %d\n", (int) sizeof(time_t));et évitez le zproblème.
chux
6
Sous Visual Studio 2008, il est par défaut un __int64sauf si vous le définissez _USE_32BIT_TIME_T. Vous feriez mieux de prétendre simplement que vous ne savez pas ce qu'elle est définie, car elle peut (et va) changer de plateforme en plateforme.
Cela fonctionne généralement, mais si votre programme est destiné à garder une trace des événements qui se produiront dans 30 ans, il est assez important que vous n'ayez pas de time_t 32 bits signé.
Rob Kennedy
4
@Rob, bah, laisse-le! Nous allons commencer à courir comme des poulets sans tête en 2036, comme nous l'avons fait pour Y2K. Certains d'entre nous gagneront beaucoup d'argent en étant des consultants Y2k38, Leonard Nimoy sortira un autre livre hilarant sur la façon dont nous devrions tous aller nous cacher dans la forêt ...
paxdiablo
1
... et tout va exploser, le public se demandant de quoi il s'agit. Je peux même sortir de la retraite pour gagner de l'argent pour l'héritage des enfants :-).
paxdiablo
2
BTW, nous n'avons trouvé qu'un seul bug Y2K et c'était une page Web qui indiquait la date au 1er janvier 19100. Exercice pour le lecteur pour savoir pourquoi ...
paxdiablo
9
Si l'événement qui se produira dans 30 ans est "expirer cette sauvegarde", alors vous pourriez avoir des problèmes MAINTENANT, pas en 2038. Ajoutez 30 ans au time_t 32 bits d'aujourd'hui, et vous obtenez une date dans le passé. Votre programme recherche les événements à traiter, en trouve un qui est en retard (de 100 ans!) Et l'exécute. Oups, plus de sauvegarde.
Rob Kennedy
5
time_test de type long intsur les machines 64 bits, sinon il l'est long long int.
Vous pouvez le vérifier dans ces fichiers d'en-tête:
(Les instructions ci-dessous ne sont pas les unes après les autres. Elles peuvent être trouvées dans le fichier d'en-tête resp. En utilisant la recherche Ctrl + f.)
Il s'agit d'un type entier signé 32 bits sur la plupart des plates-formes héritées. Cependant, cela fait souffrir votre code du bogue de l' année 2038 . Ainsi, les bibliothèques C modernes devraient plutôt le définir comme un int 64 bits signé, ce qui est sûr pendant quelques milliards d'années.
En général, vous trouverez ces typedefs spécifiques à l'implémentation sous-jacents pour gcc dans le répertoire bitsou en- asmtête. Pour moi, c'est/usr/include/x86_64-linux-gnu/bits/types.h .
Espèce C time_tpour être un vrai type commedouble, long long, int64_t, int , etc.
Cela pourrait même être unsignedcomme les valeurs de retour de nombreuses fonctions de temps indiquant que l'erreur ne l'est pas -1, mais(time_t)(-1) - Ce choix d'implémentation est rare.
Le fait est que le "besoin de connaître" le type est rare. Le code doit être écrit pour éviter le besoin.
Pourtant, un «besoin de savoir» commun se produit lorsque le code veut imprimer le brut time_t. La conversion vers le type entier le plus large s'adaptera à la plupart des cas modernes.
time_t now =0;
time(&now);
printf("%jd",(intmax_t) now);// or
printf("%lld",(longlong) now);
La conversion vers un doubleou long doublefonctionnera également, mais pourrait fournir une sortie décimale inexacte
J'ai besoin de connaître la situation car j'ai besoin de transférer du temps d'un système ARM vers un système AMD64. time_t représente 32 bits sur le bras et 64 bits sur le serveur. si je traduis l'heure dans un format et envoie une chaîne, c'est inefficace et lent. Par conséquent, il est préférable d'envoyer simplement le time_t entier et de le trier du côté serveur. Cependant, je dois comprendre un peu plus le type parce que je ne veux pas que le nombre soit altéré par une endianité différente entre les systèmes, donc j'ai besoin d'utiliser htonl ... mais d'abord, sur une base de besoin de savoir, je veux pour découvrir le type sous-jacent;)
Chouette
Un autre cas de «besoin de savoir», du moins pour les signés et les non signés, est de savoir si vous devez faire attention lors de la soustraction des temps. Si vous "soustrayez et imprimez le résultat", vous obtiendrez probablement ce que vous attendez sur un système avec un time_t signé, mais pas avec un time_t non signé.
Michael Firth
@MichaelFirth Il existe des cas pour time_t entier signé et time_t non signé où la soustraction brute entraînera des résultats inattendus. C prévoit double difftime(time_t time1, time_t time0)une approche de soustraction uniforme.
chux
-3
time_test juste typedefpour 8 octets ( long long/__int64) que tous les compilateurs et les systèmes d'exploitation comprennent. À l'époque, c'était juste pour long int(4 octets) mais pas maintenant. Si vous regardez time_tdans, crtdefs.hvous trouverez les deux implémentations mais le système d'exploitation les utilisera long long.
tous les compilateurs et OS? Non. Sur mon système Linux, le compilateur prend l'implémentation signée de 4 octets.
Vincent
Sur les systèmes Zynq 7010, time_t est de 4 octets.
Owl
1
Sur les systèmes embarqués, je travaille sur time_t soit presque toujours 32 bits ou 4 octets. La norme indique spécifiquement qu'elle est spécifique à l'implémentation, ce qui rend cette réponse tout simplement fausse.
long int
.Réponses:
L' article de Time_t sur Wikipédia apporte un éclairage à ce sujet. L'essentiel est que le type de
time_t
n'est pas garanti dans la spécification C.la source
time_t
dans la structure de données sur disque peut se produire. Cependant, comme les systèmes de fichiers sont souvent lus par d'autres systèmes d'exploitation, il serait idiot de définir le système de fichiers en fonction de ces types dépendants de l'implémentation. Par exemple, le même système de fichiers peut être utilisé à la fois sur des systèmes 32 bits et 64 bits ettime_t
peut changer de taille. Ainsi, les systèmes de fichiers doivent être définis plus précisément ("Entier signé 32 bits donnant le nombre de secondes depuis le début de 1970, en UTC") que tout commetime_t
.time.h
contenus. Cet article renvoie à cppreference.com mais le contenu cité est introuvable…time_t
signature est incorrecte. pubs.opengroup.org/onlinepubs/9699919799/basedefs/… dicte que diverses choses doivent être un "type entier signé" ou "type entier non signé", maistime_t
cela dit simplement qu'il "doit être un type entier" . Une implémentation peut êtretime_t
non signée et toujours conforme à POSIX.[root]# cat time.c
[root]# gcc -E time.c | grep __time_t
typedef long int __time_t;
Il est défini
$INCDIR/bits/types.h
par:la source
typedef __int32_t __time_t;
ettypedef __time_t time_t;
dans unFreeBSD 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
. Vos résultats sont explicitement définis comme cela sous Linux (au moins sur 2.6.32-5-xen-amd64 de Debian).__time_t
et netime_t
pas trouver le type sous-jacent detime_t
? Omettre une étape?typedef __time_t time_t;
, l'examen du code environnant est également nécessaire pour s'assurer que typedef a bien été utilisé et pas seulement une partie d'une compilation conditionnelle.typedef long time_t;
peut avoir été trouvé aussi.Normes
William Brendel a cité Wikipedia, mais je le préfère de la bouche du cheval.
Le projet de norme C99 N1256 7.23.1 / 3 "Composantes du temps" dit:
et 6.2.5 / 18 "Types" dit:
POSIX 7 sys_types.h dit:
où
[CX]
est défini comme :C'est une extension car elle apporte une garantie plus forte: les virgules flottantes sont sorties.
gcc one-liner
Pas besoin de créer un fichier comme mentionné par Quassnoi :
Sur Ubuntu 15.10 GCC 5.2, les deux premières lignes sont:
Répartition des commandes avec quelques citations de
man gcc
:-E
: "Arrêtez après l'étape de prétraitement; n'exécutez pas le compilateur correctement."-xc
: Spécifiez le langage C, car l'entrée provient de stdin qui n'a pas d'extension de fichier.-include file
: "Traiter le fichier comme si" #include "file" "apparaissait comme la première ligne du fichier source principal."-
: entrée de stdinla source
gcc -E -xc -include time.h /dev/null | grep time_t
La réponse est définitivement spécifique à l'implémentation. Pour connaître définitivement votre plateforme / compilateur, ajoutez simplement cette sortie quelque part dans votre code:
Si la réponse est 4 (32 bits) et que vos données doivent dépasser 2038 , vous disposez de 25 ans pour migrer votre code.
Vos données seront correctes si vous stockez vos données sous forme de chaîne, même si c'est quelque chose de simple comme:
Ensuite, lisez-le de la même manière (fread, fscanf, etc. dans un int), et vous avez votre temps de décalage d'époque. Une solution de contournement similaire existe dans .Net. Je passe des numéros d'époque 64 bits entre les systèmes Win et Linux sans problème (sur un canal de communication). Cela soulève des problèmes d'ordre des octets, mais c'est un autre sujet.
Pour répondre à la requête de paxdiablo, je dirais qu'il a imprimé "19100" parce que le programme a été écrit de cette façon (et j'avoue que je l'ai fait moi-même dans les années 80):
L'
printf
instruction imprime la chaîne fixe "Year is: 19" suivie d'une chaîne à zéro avec les "années depuis 1900" (définition detm->tm_year
). En 2000, cette valeur est 100, évidemment."%02d"
tampons avec deux zéros mais ne tronquent pas si plus de deux chiffres.La façon correcte est (passer à la dernière ligne uniquement):
Nouvelle question: quelle est la justification de cette réflexion?
la source
%zu
spécificateur de format pour formater lessize_t
valeurs (telles que fournies parsizeof
), car elles sont non signées (u
) et de longueur size_t (z
) ·printf ("sizeof time_t is: %d\n", (int) sizeof(time_t));
et évitez lez
problème.Sous Visual Studio 2008, il est par défaut un
__int64
sauf si vous le définissez_USE_32BIT_TIME_T
. Vous feriez mieux de prétendre simplement que vous ne savez pas ce qu'elle est définie, car elle peut (et va) changer de plateforme en plateforme.la source
time_t
est de typelong int
sur les machines 64 bits, sinon il l'estlong long int
.Vous pouvez le vérifier dans ces fichiers d'en-tête:
time.h
:/usr/include
types.h
ettypesizes.h
:/usr/include/x86_64-linux-gnu/bits
(Les instructions ci-dessous ne sont pas les unes après les autres. Elles peuvent être trouvées dans le fichier d'en-tête resp. En utilisant la recherche Ctrl + f.)
1) Dans
time.h
2) Dans
types.h
3) Dans
typesizes.h
4) Encore une fois
types.h
la source
long int
partout. Voir stackoverflow.com/questions/384502/…Il s'agit d'un type entier signé 32 bits sur la plupart des plates-formes héritées. Cependant, cela fait souffrir votre code du bogue de l' année 2038 . Ainsi, les bibliothèques C modernes devraient plutôt le définir comme un int 64 bits signé, ce qui est sûr pendant quelques milliards d'années.
la source
En général, vous trouverez ces typedefs spécifiques à l'implémentation sous-jacents pour gcc dans le répertoire
bits
ou en-asm
tête. Pour moi, c'est/usr/include/x86_64-linux-gnu/bits/types.h
.Vous pouvez simplement grep, ou utiliser une invocation de préprocesseur comme celle suggérée par Quassnoi pour voir quel en-tête spécifique.
la source
Le code robuste ne se soucie pas du type.
Espèce C
time_t
pour être un vrai type commedouble, long long, int64_t, int
, etc.Cela pourrait même être
unsigned
comme les valeurs de retour de nombreuses fonctions de temps indiquant que l'erreur ne l'est pas-1
, mais(time_t)(-1)
- Ce choix d'implémentation est rare.Le fait est que le "besoin de connaître" le type est rare. Le code doit être écrit pour éviter le besoin.
Pourtant, un «besoin de savoir» commun se produit lorsque le code veut imprimer le brut
time_t
. La conversion vers le type entier le plus large s'adaptera à la plupart des cas modernes.La conversion vers un
double
oulong double
fonctionnera également, mais pourrait fournir une sortie décimale inexactela source
double difftime(time_t time1, time_t time0)
une approche de soustraction uniforme.time_t
est justetypedef
pour 8 octets (long long/__int64
) que tous les compilateurs et les systèmes d'exploitation comprennent. À l'époque, c'était juste pourlong int
(4 octets) mais pas maintenant. Si vous regardeztime_t
dans,crtdefs.h
vous trouverez les deux implémentations mais le système d'exploitation les utiliseralong long
.la source