mon propre asctime()

Voir le sujet précédent Voir le sujet suivant Aller en bas

mon propre asctime()

Message  Zelwina le Sam 6 Sep 2008 - 5:10

Salut salut les gens !

Voilà, j'expose le problème : asctime() est bien jolie, mais trop anglophone pour moi, et surtout, elle renvoie des choses inutiles pour moi, du coup, j'me suis dit que ce s erait sympa de coder ma propre asctime.

La voici :
Code:
void chainageDate(char *date, struct tm *tm)
{
    char jour[5],jourdm[4], mois[6], annee[6], heure[5], min[5], sec[5];
    int human_year=1900+(tm->tm_year);

    sprintf(jourdm, "%d ", tm->tm_mday);
    sprintf(annee, "%d ", human_year);
    sprintf(heure, "%d:", tm->tm_hour);
    sprintf(min, "%d:", tm->tm_min);
    sprintf(sec, "%d", tm->tm_sec);

    switch (tm->tm_wday)
    {
        case 0:
        sprintf(jour, "Dim ");
        break;

        case 1:
        sprintf(jour, "Lun ");
        break;
        case 2:

        sprintf(jour, "Mar ");
        break;

        case 3:
        sprintf(jour, "Mer ");
        break;

        case 4:
        sprintf(jour, "Jeu ");
        break;

        case 5:
        sprintf(jour, "Ven ");
        break;

        case 6:
        sprintf(jour, "Ven ");
        break;

        default:
        sprintf(jour, " ");
        break;
    }

    switch(tm->tm_mday)
    {
        case 0:
        sprintf(mois, "Janv ");
        break;

        case 1:
        sprintf(mois, "Fev ");
        break;

        case 2:
        sprintf(mois, "Mars ");
        break;

        case 3:
        sprintf(mois, "Avr ");
        break;

        case 4:
        sprintf(mois, "Mai ");
        break;

        case 5:
        sprintf(mois, "Juin ");
        break;

        case 6:
        sprintf(mois, "Juil ");
        break;

        case 7:
        sprintf(mois, "Aout ");
        break;

        case 8:
        sprintf(mois, "Sept ");
        break;

        case 9:
        sprintf(mois, "Oct ");
        break;

        case 10:
        sprintf(mois, "Nov ");
        break;

        case 11:
        sprintf(mois, "Dec ");
        break;

        default:
        sprintf(mois, " ");
        break;
    }

    strcpy(date, jour);
    strcat(date, jourdm);
    strcat(date, mois);
    strcat(date, annee);
    strcat(date, heure);
    strcat(date, min);
    strcat(date, sec);
}

Bon pas de problème, de warning ou autre, seulement voilà, il se trouve que nous sommes "Sam 6 sept 2008 04:04:XX" et, horreur :

Ven 6 Juil 2008, 4:4:12

Ajouter des "0" pour la lisibilité ne me pose pas de problème, le fait que mon code remonte le temps par contre, oui ^^'
Faut-il que je bidouille avec local.h pour avoir quelque chose de portable ou alors abandonner de suite et juste modifier le char* renvoyé par asctime() ?

Merci d'avance !

PS : un thread présentation serait sympa non ? =P

Zelwina

Messages : 3
Date d'inscription : 06/09/2008
Age : 29
Localisation : France

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: mon propre asctime()

Message  -ed- le Dim 7 Sep 2008 - 20:50

Zelwina a écrit:Voilà, j'expose le problème : asctime() est bien jolie, mais trop anglophone pour moi, et surtout, elle renvoie des choses inutiles pour moi, du coup, j'me suis dit que ce s erait sympa de coder ma propre asctime.
<...>
Bon pas de problème, de warning ou autre, seulement voilà, il se trouve que nous sommes "Sam 6 sept 2008 04:04:XX" et, horreur :

Ven 6 Juil 2008, 4:4:12

Ajouter des "0" pour la lisibilité ne me pose pas de problème, le fait que mon code remonte le temps par contre, oui
Presque correct. Il y a 2 points à améliorer :

L'interface : il manque une indication de la taille de la chaine de destination. On ne peut donc pas savoir si on va déborder ou non. Ou alors, il faudrait fournir une constante 'taille minimale du tableau de char'...

La présentation :
Code:

'Dim 7 Aout 2008 19:36:4'

Process returned 0 (0x0)  execution time : 0.039 s
Press any key to continue.
Il faut mettre les 0 en tête : "%02d". Par contre, ma machine est à l'heure et indique la bonne heure et date. Tu es certains de ta machine ? Montre ton code qui initialise la structure.

J'ai trouvé un bug :
Code:

  switch (tm->tm_mday)
  {
  case 0:
      sprintf (mois, "Janv ");
      break;
C'est pas tm_mday (numéro du jour dans le mois) mais tm_mon (numéro du mois en partant de 0).

Sinon, tu fais un usage un peu trop abusif des recopies. Pour les chaines, un pointeur suffit...

Un switch-case n'est pas justifié ici, car les valeurs numériques sont connues, stables, ordonnées, consécutives et partant de 0. Bref (et ce n'est certainement pas un hasard), des candidats parfaits pour un indice de tableau. Un tableau de chaine suffit donc.

Ca donnerait
Code:

#include <stdio.h>
#include <string.h>
#include <time.h>

int chainageDate (char *date, size_t size, struct tm const *tm)
{
  /* compte rendu d'erreur */
  int err = 0;

  /* tableaux de chaines */
  static char const *a_days[] =
      { "Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", };
  static char const *a_months[] =
      { "Janv", "Fev", "Mars", "Avr", "Mai", "Juin", "Juil", "Aout", "Sept",
      "Oct", "Nov", "Dec"
  };

  char const *jour, *mois;

  /* calcul de l'annee julienne */
  int human_year = 1900 + (tm->tm_year);

  /* recuperation du jour en texte */
  if ((unsigned) tm->tm_wday < 7)
  {
      jour = a_days[tm->tm_wday];
  }
  else
  {
      jour = "???";
      err = 1;
  }

  /* recuperation du mois en texte */
  if ((unsigned) tm->tm_mon < 12)
  {
      mois = a_months[tm->tm_mon];
  }
  else
  {
      mois = "???";
      err = 1;
  }

  /* verification de la taille */
  if (sizeof "jjj jj aaaa hh:mm:ss" + strlen (mois) <= size)
  {
      /* creation de la chaine */
      sprintf (date, "%s %d %s %d %02d:%02d:%02d", jour, tm->tm_mday, mois,
              human_year, tm->tm_hour, tm->tm_min, tm->tm_sec);
  }
  else
  {
      err = 1;
  }
  return err;

}

int main (void)
{
  char s[25];

  time_t now = time (NULL);
  struct tm tm = *localtime (&now);
  int err = chainageDate (s, sizeof s, &tm);
  if (!err)
  {
      printf ("'%s' (%u car)\n", s, (unsigned) strlen (s));
  }
  else
  {
      printf ("error\n");
  }
  return 0;
}
Code:

'Dim 7 Sept 2008 20:22:37' (24 car)

Process returned 0 (0x0)  execution time : 0.035 s
Press any key to continue.
Faut-il que je bidouille avec local.h pour avoir quelque chose de portable
Ce serait certainement la meilleure solution...

Ceci devrait fonctionner :
Code:

#include <stdio.h>
#include <time.h>
#include <string.h>
#include <locale.h>

int main (void)
{
  setlocale (LC_ALL, "fr_FR");
  {
      char s[25];
      time_t now = time (NULL);
      struct tm tm = *localtime (&now);
      strftime (s, sizeof s, "%a %d %b %Y %H:%M:%S", &tm);

      printf ("'%s' (%u car)\n", s, (unsigned) strlen (s));
  }
  return 0;
}
Mais en pratique, avec MinGW sous Vista, ça ne fonctionne pas :
Code:

'Sun 07 Sep 2008 20:55:38' (24 car)

Process returned 0 (0x0)  execution time : 0.040 s
Press any key to continue.

-ed-
Admin
Admin

Messages : 289
Date d'inscription : 26/05/2008
Age : 60
Localisation : Paris 6eme arrondissement (75, France)

Voir le profil de l'utilisateur http://bien-programmer.fr

Revenir en haut Aller en bas

Re: mon propre asctime()

Message  Zelwina le Sam 13 Sep 2008 - 0:35

Tout d'abord, je tiens à m'excuser pour ne pas avoir répondu plus tôt (travail tout ça, 'fin bon).

L'interface : il manque une indication de la taille de la chaine de destination. On ne peut donc pas savoir si on va déborder ou non. Ou alors, il faudrait fournir une constante 'taille minimale du tableau de char'...

Par défaut, j'utilise un define TAILLE_MAX de 1000, j'ai oublié de le préciser ^^'

Il faut mettre les 0 en tête : "%02d". Par contre, ma machine est à l'heure et indique la bonne heure et date. Tu es certains de ta machine ? Montre ton code qui initialise la structure.

Ce qui signifie, si j'ai bien compris : "tu mets un 0 si jamais il y a moins de deux chiffres", j'avais envisager une autre solution plus longue, nettement plus longue, je dois avouer que je ne connais pas encore toutes les subtilités de ce type de fonction (variadic, si je ne m'abuse, mais j'ai peur de dire une bêtise, corrige moi si je me trompe).

Ensuite, le bug est corrigé, c'est fou ce qu'on n'arrive pas à voir dans son propre code >___<.

Et maintenant, la partie la plus intéressante :

Code:
#include <stdio.h>
#include <string.h>
#include <time.h>

int chainageDate (char *date, size_t size, struct tm const *tm)
{
  /* compte rendu d'erreur */
  int err = 0;

  /* tableaux de chaines */
  static char const *a_days[] =
      { "Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", };
  static char const *a_months[] =
      { "Janv", "Fev", "Mars", "Avr", "Mai", "Juin", "Juil", "Aout", "Sept",
      "Oct", "Nov", "Dec" };

  char const *jour, *mois;

  /* calcul de l'annee julienne */
  int human_year = 1900 + (tm->tm_year);

  /* recuperation du jour en texte */
  if ((unsigned) tm->tm_wday < 7)
  {
      jour = a_days[tm->tm_wday];
  }
  else
  {
      jour = "???";
      err = 1;
  }

  /* recuperation du mois en texte */
  if ((unsigned) tm->tm_mon < 12)
  {
      mois = a_months[tm->tm_mon];
  }
  else
  {
      mois = "???";
      err = 1;
  }

  /* verification de la taille */
  if (sizeof "jjj jj aaaa hh:mm:ss" + strlen (mois) <= size)
  {
      /* creation de la chaine */
      sprintf (date, "%s %d %s %d %02d:%02d:%02d", jour, tm->tm_mday, mois,
              human_year, tm->tm_hour, tm->tm_min, tm->tm_sec);
  }
  else
  {
      err = 1;
  }
  return err;

}

int main (void)
{
  char s[25];

  time_t now = time (NULL);
  struct tm tm = *localtime (&now);
  int err = chainageDate (s, sizeof s, &tm);
  if (!err)
  {
      printf ("'%s' (%u car)\n", s, (unsigned) strlen (s));
  }
  else
  {
      printf ("error\n");
  }
  return 0;
}

/* tableaux de chaines */
static char const *a_days[] =
{ "Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", };
static char const *a_months[] =
{ "Janv", "Fev", "Mars", "Avr", "Mai", "Juin", "Juil", "Aout", "Sept",
"Oct", "Nov", "Dec" };

C'est la première fois que je vois ça, je ne connais pas mais je pense saisir le fonctionnement seul : const est transparant et *xxx[] ={...}; permet d'initialiser un tableau pour lequel on a un pointeur sur chaque élément ; par contre, j'ai du mal avec le static, et ce, de manière général, je ne comprends pas son utilité, que ce soit dans pour une fonction, ou pour un variable.
Je suppose également qu'il est possible de faire un tableau chainé de tout type de variable ? de plusieurs dimension ? de structure ?

if ((unsigned) tm->tm_wday < 7)

Hummm pourquoi ce unsigned entre parenthèses ?

Wouala, c'est toutes les questions qui m'assaillent lorsque je vois ce magnifique code qui condense un pavé aussi lourd à l'écriture qu'à la lecture =P

Je te remercie de ta patience et demande encore une fois d'excuser mon absence :x

Zelwina

Messages : 3
Date d'inscription : 06/09/2008
Age : 29
Localisation : France

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: mon propre asctime()

Message  -ed- le Sam 13 Sep 2008 - 1:07

Zelwina a écrit:Ce qui signifie, si j'ai bien compris : "tu mets un 0 si jamais il y a moins de deux chiffres",
Oui, c'est ce que fait ce mode de formatage de printf() (oui, c'est une fonction variadic).

Code:
/* tableaux de chaines */
  static char const *a_days[] =
      { "Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", };
  static char const *a_months[] =
      { "Janv", "Fev", "Mars", "Avr", "Mai", "Juin", "Juil", "Aout", "Sept",
      "Oct", "Nov", "Dec" };

C'est la première fois que je vois ça, je ne connais pas mais je pense saisir le fonctionnement seul : const est transparant
transparent ? Tu veux dire inutile ? Non. Il dit clairement au compilateurs que les pointeurs du tableau pointent sur des zones de code non modifiables (chaines de caractères). Ca devient plus clair quand on a compris la suite :
et *xxx[] ={...}; permet d'initialiser un tableau pour lequel on a un pointeur sur chaque élément ;
Oui.
par contre, j'ai du mal avec le static, et ce, de manière général, je ne comprends pas son utilité, que ce soit dans pour une fonction, ou pour un variable.
N'oublie pas qu'il y a beaucoup de réponses sur lonsite...

http://mapage.noos.fr/emdel/notes.htm#static

Je suppose également qu'il est possible de faire un tableau chainé de tout type de variable ?
Je ne sais pas ce qu'est un 'tableau chainé'

Code:
 if ((unsigned) tm->tm_wday < 7)

Hummm pourquoi ce unsigned entre parenthèses ?
La valeur de tm->tm_wday est de type int. Pour éviter de tester le cas 'if ... < 0', je convertis le int en unsigned int, ce qui fait que je n'ai plus à tester ce qui est < 0, puis que ça n'existe plus. C'est converti en une valeur très supérieure à 0, donc, de toutes façons, hors limites.


Dernière édition par -ed- le Sam 13 Sep 2008 - 2:19, édité 1 fois

-ed-
Admin
Admin

Messages : 289
Date d'inscription : 26/05/2008
Age : 60
Localisation : Paris 6eme arrondissement (75, France)

Voir le profil de l'utilisateur http://bien-programmer.fr

Revenir en haut Aller en bas

Re: mon propre asctime()

Message  Zelwina le Sam 13 Sep 2008 - 1:53

Non quand je dis transparent, je veux dire const = constant, qui ne varie pas.

Et pour finir je voulais dire indice de tableau, désolé ^^'

Merci Ed !

PS : Sous peu, je risque de te faire extrêment mal, j'ai un petit projet qui va bientôt se terminer et je posterais ici un lien pour te montrer les sources. Je n'attends bien sûr pas une ré-écriture de mon code, mais plutot des pistes pour aller plus vite, pour optimiser le tout etc...

Edit = je viens de lire la partie de ton site sur "static" et je dois avouer que je ne vois toujours pas l'utilité, du moins quand il s'agit de déclarer une variable en static dans une fonction qui est, (je crois) un bloc de compilation. (pour être plus précis, je crois qu'un bloc de compilation est tout ce qui se trouve entre deux accolades, seulement wouala, c'est mon instinct qui me dit ça, j'approfondirai cela demain, il est plus que temps pour moi de me reposer un peu)

Zelwina

Messages : 3
Date d'inscription : 06/09/2008
Age : 29
Localisation : France

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: mon propre asctime()

Message  -ed- le Sam 13 Sep 2008 - 2:27

Zelwina a écrit:PS : Sous peu, je risque de te faire extrêment mal, j'ai un petit projet qui va bientôt se terminer et je posterais ici un lien pour te montrer les sources. Je n'attends bien sûr pas une ré-écriture de mon code, mais plutot des pistes pour aller plus vite, pour optimiser le tout etc...
Si tu veux une expertise complète de ton code, c'est faisable, mais peut être pas dans le cadre du bénévolat... Il y a des limites ! Je ne vis pas de l'air du temps...

Edit = je viens de lire la partie de ton site sur "static" et je dois avouer que je ne vois toujours pas l'utilité, du moins quand il s'agit de déclarer une variable en static dans une fonction qui est, (je crois) un bloc de compilation. (pour être plus précis, je crois qu'un bloc de compilation est tout ce qui se trouve entre deux accolades, seulement wouala, c'est mon instinct qui me dit ça, j'approfondirai cela demain, il est plus que temps pour moi de me reposer un peu)
Ici, 'static 's'applique à la définition d'un tableau dans une fonction. Ça signifie que le tableau est défini dans une zone mémoire dite 'statique', c'est à dire qui est initialisée une fois avant l'exécution du main(). En effet, pour cette application, il n'est pas nécessaire d'encombrer la mémoire automatique (ressource rare) d'un tableau de pointeurs qu'il va falloir initialiser à chaque fois... Non. Le tableau est crée et initialisé une fois pour toutes, et on y a accès uniquement dans cette fonction.

-ed-
Admin
Admin

Messages : 289
Date d'inscription : 26/05/2008
Age : 60
Localisation : Paris 6eme arrondissement (75, France)

Voir le profil de l'utilisateur http://bien-programmer.fr

Revenir en haut Aller en bas

Re: mon propre asctime()

Message  Contenu sponsorisé Aujourd'hui à 21:18


Contenu sponsorisé


Revenir en haut Aller en bas

Voir le sujet précédent Voir le sujet suivant Revenir en haut

- Sujets similaires

 
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum