IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Notes sur le langage C

Notes sur le langage C


précédentsommairesuivant

XXXV. <time.h> : La gestion du temps

XXXV-A. Introduction

Le langage C fournit un certain nombre de fonctions permettant de lire l'heure/date courante et de convertir la valeur lue en structure ou en chaine de caractères. Ces éléments sont définis et déclarés dans le header standard <time.h>

Elément Nature Description
struct tm structure Structure de date et heure
time() fonction Lecture de l'heure courante
time_t type Type retourné par time()
localtime() fonction Charge la structure tm avec l'heure locale
gmtime() fonction Charge la structure tm avec l'heure GMT
mktime() fonction Normalise la structure tm
Retourne le temps en time_t
strftime() fonction Créee une chaine formatée à partir d'une structure tm
difftime() fonction Calcule la différence entre 2 dates

XXXV-B. Usage

XXXV-B-1. Lire l'heure courante

On utilise la fonction time(). On peut soit passer l'adresse d'un time_t, soit récupérer la valeur dans un time_t. Si on utilise pas l'adresse d'un time_t, il faut le préciser à la fonction en passant NULL :

 
Sélectionnez
#include <time.h>
 
int main (void)
{
   time_t ta;
   time_t tb;
 
   time (&ta);
   tb = time (NULL);
 
   return 0;
}

Telle quelle, la valeur contenue dans ta et tb n'a pas grande signification. La norme dit que c'est un grand entier qui représente un nombre d'élément de temps depuis une date donnée. Sous POSIX.1, c'est un nombre de secondes depuis le 1er janvier 1970. (Epoch). En principe, on ne manipule pas la valeur directement, mais via sa représentation en struct tm.

Cette valeur a quand même un intérêt pratique. Il y a de fortes chances qu'elle soit différente d'un lancement de programme à l'autre. On l'utilise donc courrament pour initialiser le générateur pseudo-aléatoire du C avec une valeur différente à chaque lancement :

 
Sélectionnez
 srand((unsigned) time(NULL));

ce qui permet de démarrer le cycle de la séquence pseudo-aléatoire à un endroit difficilement prévisible, renforçant ainsi l'effet 'aléatoire' pour les jeux et autres programmes statistiques.

XXXV-B-2. Afficher l'heure courante

L'affichage de la date ou de l'heure de fait grace à la fonction strftime() qui a été conçue pour ça. Elle attend l'adresse d'une structure tm, qu'il va donc falloir mettre à jour au préalable. On utilise pour ça la valeur retournée par time(), qui donne la datation courante sous la forme d'un entier et une des fonction localtime() ou gmtime() selon que l'on veut convertir en heure locale ou en heure GMT (Greenwich). En France, il y a une heure de différence.

L'usage précis de strftime() et de ses nombreux paramètres de formatage doit être étudié dans un document de référence.

 
Sélectionnez
#include <stdio.h>
#include <time.h>
 
int main (void)
{
   /* lire l'heure courante */
   time_t now = time (NULL);
 
   /* la convertir en heure locale */
   struct tm tm_now = *localtime (&now);
 
   /* Creer une chaine JJ/MM/AAAA HH:MM:SS */
   char s_now[sizeof "JJ/MM/AAAA HH:MM:SS"];
 
   strftime (s_now, sizeof s_now, "%d/%m/%Y %H:%M:%S", &tm_now);
 
   /* afficher le resultat : */
   printf ("'%s'\n", s_now);
 
   return 0;
}
 
Sélectionnez
'29/01/2009 02:34:00'
 
Process returned 0 (0x0)   execution time : 0.054 s
Press any key to continue.

XXXVI. <time.h> : bien utiliser difftime()

Les fonctions de <time.h> offrent une interface assez complexe. Voici un exemple qui rassemble l'usage de la plupart de ces fonctions.

 
Sélectionnez
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
 
int main (void)
{
   time_t now = time (NULL);
   struct tm tm_now = *localtime (&now);
   char s[64];
 
   strftime (s, sizeof s, "%d/%m/%Y", &tm_now);
   printf ("Aujourd'hui : %s\n", s);
 
 
   /* prochain Noel */
   {
      struct tm tm_xmas =
      {0};
 
      tm_xmas.tm_year = tm_now.tm_year;
      tm_xmas.tm_mon = 12 - 1;
      tm_xmas.tm_mday = 25;
 
      /* ajustement */
      {
         time_t xmas = mktime (&tm_xmas);
 
         strftime (s, sizeof s, "%d/%m/%Y", &tm_xmas);
         printf ("Noel : %s\n", s);
 
         {
            time_t diff = difftime (xmas, now);
            struct tm tm_diff = *gmtime (&diff);
 
            printf ("Plus que %d jours avant Noel\n", tm_diff.tm_yday);
         }
      }
   }
 
   return 0;
}

XXXVII. rand(), srand()... j'y comprends rien...

Un générateur pseudo-aléatoire est une machine qui génère une séquence de nombres déterminée, cyclique, mais difficile à prévoir pour un humain. De plus, la répartition des valeurs (histogramme) est supposée être équilibrée.

La génération n'est pas 'spontanée', mais 'à la demande' (par appel de la fonction rand()). Les valeurs produites sont comprises entre 0 et RAND_MAX inclus.

A chaque fois que l'on appelle rand(), une nouvelle valeur sort :

 
Sélectionnez
#include <stdio.h>
#include <stdlib.h>
 
int main (void)
{
   int i;
   printf ("Les valeurs vont de 0 a %d\n", RAND_MAX);
   for (i = 0; i < 10; i++)
   {
      int val = rand ();
      printf ("%d ", val);
   }
   printf ("\n");
   return 0;
}

Par exemple :

 
Sélectionnez
Les valeurs vont de 0 à 32767
41 18467 6334 26500 19169 15724 11478 29358 26962 24464

Mais on constate que si on lance le programme plusieurs fois, la séquence est toujours la même.

On peut modifier l'origine de la séquence avec srand(), en passant une valeur comprise entre 0 et RAND_MAX. Par exemple 10 :

 
Sélectionnez
#include <stdio.h>
#include <stdlib.h>
 
int main (void)
{
   int i;
 
   srand(10); /* MODIF */
 
   printf ("Les valeurs vont de 0 a %d\n", RAND_MAX);
   for (i = 0; i < 10; i++)
   {
      int val = rand ();
      printf ("%d ", val);
   }
   printf ("\n");
   return 0;
}

On constate que les valeurs sont différentes du tirage précédent, mais que si on relance le programme, elles restent identiques :

 
Sélectionnez
Les valeurs vont de 0 à 32767
71 16899 3272 13694 13697 18296 6722 3012 11726 1899

Pour avoir une séquence différente à chaque lancement du programme, il faut donc trouver un moyen de passer une valeur 'changeante' à srand(), d'où l'idée d'utiliser la valeur retournée par time(), qui change une fois par seconde, indépendamment du programme (c'est une valeur gérée par le système).

Une seconde, c'est long, mais ça suffit pour les besoins courants.

 
Sélectionnez
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
 
int main (void)
{
   int i;
 
   srand((unsigned) time(NULL)); /* MODIF */
 
   printf ("Les valeurs vont de 0 a %d\n", RAND_MAX);
   for (i = 0; i < 10; i++)
   {
      int val = rand ();
      printf ("%d ", val);
   }
   printf ("\n");
   return 0;
}

Si on lance plusieurs fois le programme (au moins une seconde entre chaque lancement), on obtient maintenant des séquences différentes :

 
Sélectionnez
25985 16903 23861 29724 17917 23752 17039 25712 20507 30816
26197 27421 5384 20976 236 16846 22741 32047 12417 24408
26433 14874 13653 16830 21990 4658 17461 17892 21603 7731

etc. Je précise que pour que les valeurs changent dans le programme, il faut évidemment que srand() ne soit appelé qu'une seule fois au début du programme.

Après, il y a des astuces arithmétiques pour réduire la plage de valeurs... C'est du bête calcul entier... Détails dans la FAQ de f.c.l.c., notamment ici. D'autre part, ceci peut aider.


précédentsommairesuivant

Copyright © 2009 Emmanuel Delahaye. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.