web-dev-qa-db-fra.com

A quoi sert finalement time_t un typedef?

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.

182
kal

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 standard time(). 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 que signed 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 type time_t 32 bits sont sujets à problème de l'an 2038 .

163
William Brendel

[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
104
Quassnoi

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.

[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 stdin

La 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?

12
pwrgreg007

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.

7
Eclipse

_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;
_
5
abcoep

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.

4
user

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.

3
poolie

À 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);
1
chux