Réponses:
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 latime()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 quesigned 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 bitstime_tsont sensibles au problème de l' an 2038 .
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.
time.hcontenus. Cet article renvoie à cppreference.com mais le contenu cité est introuvable…
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.
[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;
Il est défini $INCDIR/bits/types.hpar:
# 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;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).
__time_tet ne time_tpas trouver le type sous-jacent de time_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:
Les types déclarés sont size_t (décrit en 7.17) clock_t et time_t qui sont des types arithmétiques capables de représenter des temps
et 6.2.5 / 18 "Types" dit:
Les types entiers et flottants sont appelés collectivement types arithmétiques.
POSIX 7 sys_types.h dit:
[CX] time_t doit être un type entier.
où [CX]est défini comme :
[CX] Extension à la norme ISO C.
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 :
echo | gcc -E -xc -include 'time.h' - | grep time_t
Sur Ubuntu 15.10 GCC 5.2, les deux premières lignes sont:
typedef long int __time_t;
typedef __time_t time_t;
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 stdingcc -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:
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?
%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) ·
printf ("sizeof time_t is: %d\n", (int) sizeof(time_t));et évitez le zproblème.
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.
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:
time.h: /usr/include
types.het typesizes.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
typedef __time_t time_t;
2) Dans types.h
# define __STD_TYPE typedef
__STD_TYPE __TIME_T_TYPE __time_t;
3) Dans 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) Encore une fois 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 intpartout. 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.
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 .
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.
À quoi sert finalement un typedef time_t?
Le code robuste ne se soucie pas du type.
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", (long long) now);
La conversion vers un doubleou long doublefonctionnera également, mais pourrait fournir une sortie décimale inexacte
printf("%.16e", (double) now);
double difftime(time_t time1, time_t time0)une approche de soustraction uniforme.
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.
long int.