J'ai cherché ma machine Linux et ai vu ce typedef:
typedef __time_t time_t;
Mais je n'ai pas trouvé la définition de __time_t
.
L’article article Wikipedia de time_t jette la lumière sur ce point. En fin de compte, le type de time_t
n'est pas garanti dans la spécification C.
Le type de données
time_t
est un type de données de la bibliothèque ISO C défini pour le stockage des valeurs de l'heure système. Ces valeurs sont renvoyées par la fonction de bibliothèque standardtime()
. Ce type est un typedef défini dans l'en-tête standard. ISO C définit time_t en tant que type arithmétique, mais ne spécifie aucun type particulier , plage, résolution ou codage pour celui-ci. Les significations des opérations arithmétiques appliquées aux valeurs temporelles sont également non spécifiées.Les systèmes compatibles Unix et POSIX implémentent le type
time_t
en tant quesigned integer
(généralement de 32 ou 64 bits de large), ce qui représente le nombre de secondes écoulées depuis le début de l'Unix. Époque : minuit UTC du 1er janvier 1970 (sans compter les secondes intercalaires). Certains systèmes gèrent correctement les valeurs de temps négatives, d’autres pas. Les systèmes utilisant un typetime_t
32 bits sont sujets à problème de l'an 2038 .
[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 dans $INCDIR/bits/types.h
à travers:
# 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
Normes
William Brendel a cité Wikipedia, mais je le préfère de la bouche du cheval.
Projet de norme C99 N1256 7.23.1/3 "Composantes du temps" dit:
Les types déclarés sont size_t (décrits au 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 entier et flottant sont collectivement appelés 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 parce que cela donne une garantie plus forte: les points flottants sont sortis.
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;
Décomposition de la commande avec quelques citations de man gcc
:
-E
: "Arrêtez-vous après l'étape du prétraitement; n'exécutez pas le compilateur correctement."-xc
: Spécifiez le langage C, puisque l'entrée provient de stdin qui n'a pas d'extension de fichier.-include file
: "Le fichier de traitement comme si" #include "fichier" "apparaissait comme la première ligne du fichier source primaire."-
: entrée de stdinLa réponse est certainement spécifique à la mise en œuvre. Pour le trouver définitivement pour votre plate-forme/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 sont censées aller au-delà de 2038 , vous avez alors 25 ans pour migrer votre code.
Vos données iront bien 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, il suffit de le relire de la même manière (fread, fscanf, etc. dans un int), et vous avez le temps de décalage de votre époque. Une solution de contournement similaire existe dans .Net. Je passe les numéros Epoch 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" car 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'instruction printf
imprime la chaîne fixe "Year is: 19" suivie d'une chaîne remplie de zéros avec "years since 1900" (définition de tm->tm_year
). En 2000, cette valeur est évidemment égale à 100. "%02d"
les pads avec deux zéros mais ne tronquent pas s'ils sont plus longs que deux chiffres.
La manière correcte est (changer à la dernière ligne seulement):
printf ("Year is: %d\n", local_date_time.tm_year + 1900);
Nouvelle question: quelle est la raison de cette réflexion?
Sous Visual Studio 2008, la valeur par défaut est __int64
sauf si vous définissez _USE_32BIT_TIME_T
. Vous feriez mieux de prétendre que vous ne savez pas ce que cela signifie, car cela peut (et va) changer de plateforme en plateforme.
_time_t
_ est de type long int
sur des machines 64 bits, sinon 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 se ressemblent pas. Vous pouvez les trouver dans le fichier d'en-tête respectif à l'aide de 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 dans _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;
_
C'est un type entier signé 32 bits sur la plupart des plates-formes héritées. Cependant, votre code sera affecté par le bug de l'année 2038 . Les bibliothèques C modernes devraient donc définir ce système comme un int signé 64 bits, qui est sûr pour quelques milliards d'années.
Généralement, vous trouverez ces typedefs sous-jacentes spécifiques à l'implémentation pour gcc dans le répertoire d'en-tête bits
ou asm
. Pour moi, c'est /usr/include/x86_64-linux-gnu/bits/types.h
.
Vous pouvez simplement grep ou utiliser un appel du préprocesseur similaire à celui suggéré par Quassnoi pour voir quel en-tête spécifique.
À quoi sert finalement un time_t typedef?
Code robuste ne se soucie pas de ce que le type est.
L'espèce C time_t
doit être un type réel comme double, long long, int64_t, int
, etc.
Il peut même s'agir de unsigned
car les valeurs renvoyées par de nombreuses fonctions temporelles indiquant une erreur ne sont pas -1
, mais (time_t)(-1)
- Ce choix d'implémentation est peu commun.
Le fait est que le "besoin de savoir" du type est rare. Le code doit être écrit pour éviter le besoin.
Pourtant, un "besoin de savoir" se produit couramment lorsque le code veut imprimer le code brut time_t
. La conversion au type entier le plus large convient à la plupart des cas modernes.
time_t now = 0;
time(&now);
printf("%jd", (intmax_t) now);
// or
printf("%lld", (long long) now);
Transtyper vers un double
ou long double
fonctionnera aussi, mais pourrait fournir une sortie inexacte décimale
printf("%.16e", (double) now);