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.
Le
time_t
type 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_t
type 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_t
sont sensibles au problème de l' an 2038 .
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 et time_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 comme time_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é", mais time_t
cela dit simplement qu'il "doit être un type entier" . Une implémentation peut être time_t
non 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.h
par:
# 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_t
et ne time_t
pas 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' 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 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?
%zu
spécificateur de format pour formater les size_t
valeurs (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 z
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.
time_t
est de type long int
sur 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.h
et 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 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.
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.
À quoi sert finalement un typedef time_t?
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.
time_t now = 0;
time(&now);
printf("%jd", (intmax_t) now);
// or
printf("%lld", (long long) now);
La conversion vers un double
ou long double
fonctionnera é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_t
est juste typedef
pour 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_t
dans, crtdefs.h
vous trouverez les deux implémentations mais le système d'exploitation les utilisera long long
.
long int
.