cs_ghuysmans99
Messages postés3982Date d'inscriptionjeudi 14 juillet 2005StatutMembreDernière intervention30 juin 2013
-
30 avril 2010 à 18:23
alkandor
Messages postés4Date d'inscriptionmercredi 21 octobre 2009StatutMembreDernière intervention 3 septembre 2012
-
8 nov. 2010 à 01:08
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.
alkandor
Messages postés4Date d'inscriptionmercredi 21 octobre 2009StatutMembreDernière intervention 3 septembre 2012 8 nov. 2010 à 01:08
je v modifié le code dans un petit temp
cs_ghuysmans99
Messages postés3982Date d'inscriptionjeudi 14 juillet 2005StatutMembreDernière intervention30 juin 201316 11 juin 2010 à 21:01
@thebroyeur : si tu pouvais regarder ...
J'ai fait de nouvelles modifs. Au programme : ajout du support de l'Unicode et purification du code. Pour ce petit nettoyage de code, j'ai viré les commentaires différentiels qui ne facilitaient pas la lecture (et pis pour les modifs c'est décrit ici).
cs_ghuysmans99
Messages postés3982Date d'inscriptionjeudi 14 juillet 2005StatutMembreDernière intervention30 juin 201316 3 juin 2010 à 21:05
Oui, pas faux. Mais quand on modifie un programme en C, il n'est pas interdit de réfléchir à ce qu'on fait. Un oubli pareil ne peut passer inaperçu si l'on teste ses fonctions une fois qu'on les a modifiées. Perso je fais ça à chaque fois et je n'ai pas de problèmes (en même temps je n'ai jamais travaillé sur de gros projets en C). Cela doit néanmoins devenir un réflexe de procéder comme ça (énorme gain de temps au debugging).
Menuki
Messages postés13Date d'inscriptionlundi 10 octobre 2005StatutMembreDernière intervention11 août 2008 3 juin 2010 à 09:34
Tout à fait, je comprends très bien que ça ne sert à rien dans ce cas-ci (et dans beaucoup d'autres).
Le problème est que, si tu tolères des exceptions, tu trouveras toujours quelques "tout-fous" pour réclamer d'autres passe-droits.
Au final, tes règles de bonne conduite, censées être établies pour permettre un meilleur échange dans le groupe, ne seront qu'un ramassis de bonnes paroles.
Non, chez nous, cela fait partie de la discipline à laquelle tout le monde s'astreint (volontairement, je précise). Il est vrai que c'est un peu déroutant au début. Un oeil non habitué peut trouver cela moins lisible. Mais après peu de temps, c'est l'inverse qui se produit. Si on ne voit pas les accolades après le if, on est choqué.
Et puis, laisse-moi te raconter une histoire. Un gars de chez nous faisait la forte tête. "Je n'ai qu'une instruction, je ne mets pas d'accolade!". Un jour, il a dû rajouter une deuxième instruction à son if et... il a oublié de rajouter les accolades!
C'est moi qui ait trouvé le bug, pas lui. Comme j'étais choqué à chaque if, ça m'a sauté aux yeux.
Je pense que chez certains, c'est l'orgueil qui parle plus qu'autres choses. Ils pensent prouver leur maîtrise en utilisant toutes les subtilités du langage.
Je ne parle pas de toi. Je ne te connais pas, je ne me permettrais donc pas de te juger.
Certes, c'est bien de savoir ces choses mais si tu les appliques pour qu'au final, ça te complique la vie...
Pour ma part, je suis capable d'écrire du code ultra-condensé mais l'expérience m'a montré que 6 mois plus tard, ce qui était si clair et évident le devient beaucoup moins...
cs_ghuysmans99
Messages postés3982Date d'inscriptionjeudi 14 juillet 2005StatutMembreDernière intervention30 juin 201316 2 juin 2010 à 19:14
Sorry j'avais pas présenté la 2ème alternative :
# if (*mois > 12 || *mois < 1)
# break;
Beaucoup plus lisible du coup. Mais quand c'est comme ici une série de if avec toujours la même chose dedans, tu peux bien comprendre que ça ne serve à rien dans ce cas-ci.
Menuki
Messages postés13Date d'inscriptionlundi 10 octobre 2005StatutMembreDernière intervention11 août 2008 2 juin 2010 à 09:32
Mais pourquoi diable, cher ami Ghuysmans99, aurais-je l'intention de te taper?
Nous sommes entre programmeurs de bonne compagnie et nous savons nous tenir. :-p
Par contre, j'avoue avoir un peu mal pris le "ça tourne au ridicule".
Quand je suis arrivé dans ma boîte, un gars avait pris cette habitude (dans sa boîte précédente).
J'ai trouvé ça un peu lourd mais je m'y suis plié.
Et je me suis rendu compte que c'était beaucoup plus lisible et qu'il y avait moins de risque d'erreur.
Essaie de relire du code ancien ou lire un code d'un autre : quand la partie action de ton "if" se trouve un coup à la fin de la ligne, un coup sur la ligne en dessous, un coup entre accolades, ça devient vite prise de tête...
Quand tu fais ça au fond d'une usine, avec le client stressé derrière toi parce qu'il perd 10.000€ par minute perdue, tu as envie de tuer le type qui n'a pas suivi la charte pour faire son expert!
Ca fait partie des règles de bonne conduite de notre société et ce n'est pas négociable (notamment avec les stagiaires ;-) ).
Après, en dehors, chacun fait ce qui lui plait mais faut pas se moquer des habitudes des autres. Ils ont peut-être des bonnes raisons de faire ainsi...
cs_ghuysmans99
Messages postés3982Date d'inscriptionjeudi 14 juillet 2005StatutMembreDernière intervention30 juin 201316 1 juin 2010 à 19:03
Nouvelle proposition de code : http://pastebin.com/AP1AADHU Menuki aura probablement moins envie de me taper dessus en le voyant (enfin j'espère).
cs_ghuysmans99
Messages postés3982Date d'inscriptionjeudi 14 juillet 2005StatutMembreDernière intervention30 juin 201316 1 juin 2010 à 18:51
Mouais mais alors sans accolades décoratives ...
Là ça tourne au ridicule :
# if (*mois > 12 || *mois < 1)
# {
# break;
# }
Peut devenir :
# if (*mois > 12 || *mois < 1) break;
Menuki
Messages postés13Date d'inscriptionlundi 10 octobre 2005StatutMembreDernière intervention11 août 2008 1 juin 2010 à 14:48
Le break fait pareil (juste un jmp).
C'est pas pour une question de performance, c'est pour une question d'hygiène de vie!
C'est écrit partout sur les paquets de biscuit :
"Pour votre santé, éviter de manger sucré, salé et les goto" ;-)
Trève de plaisanterie, comme je l'ai précisé, je n'ai pas envie de rentrer dans la sempiternel gueguerre pro/anti goto. Sans les absoudre totalement, j'estime que, quand je peux faire autrement, je les évite. Et voici un moyen de les éviter (sans perte de performance en plus)...
cs_ghuysmans99
Messages postés3982Date d'inscriptionjeudi 14 juillet 2005StatutMembreDernière intervention30 juin 201316 31 mai 2010 à 18:45
Ca donne en assembleur jmp short leLabel (deux octets).
Je vois pas pourquoi on pourrait être contre un goto dans le cas présent.
Menuki
Messages postés13Date d'inscriptionlundi 10 octobre 2005StatutMembreDernière intervention11 août 2008 31 mai 2010 à 10:00
Bien! Mais je n'aime pas trop les goto.
Même si dans certains cas, c'est bien pratique, quand j'ai une autre solution, je préfère les éviter (ne transformons pas ce sujet en guerre pro-contre goto ;-) ).
Dans mes pérégrinations, j'ai découvert une pratique dans des exemples de Microsoft : la "dummy loop".
Donc voici ce que je propose pour la vérification :
void entreDate(int* jour, int* mois, int* annee)
{
for (;;)
{
printf("Date (JJ MM AAAA) : ");
scanf("%d %d %d",jour,mois,annee);
// dummy loop
do
{
if (*jour > 31 || *jour < 1)
{
break;
}
//pas de jours négatifs ou > 31
if (*mois > 12 || *mois < 1)
{
break;
}
//pas de mois négatifs ou > 12
if (*jour > 29 && *mois == 2)
{
break;
}
//pas plus de 29 jours en févrierif (!((*annee % 4 0 && *annee % 100 > 0) || (*annee % 400 0)) && (*jour > 28))
{
break;
}
//pas plus de 28 jours en février pour les années bisextilesif ((*annee < 1582) || ((*annee 1582) && (*mois < 10)) || ((*annee 1582) && (*mois == 10) && (*jour < 15)))
{
break;
}
//jours en dessous du 15/10/1582 (date de la réforme grégorienne) invalides car calendrier différent avant cette date
// si on arrive ici, c'est qu'on a réussi tous les tests, donc la date est OK
return;
}while (false); // fin de la dummy loop
printf("Date invalide.\n");
}
}
Voilà, juste une proposition...
cs_ghuysmans99
Messages postés3982Date d'inscriptionjeudi 14 juillet 2005StatutMembreDernière intervention30 juin 201316 30 mai 2010 à 18:58
Bon, mieux vaut prendre le code via Pastebin (là l'indentation n'est pas massacrée) :
http://pastebin.com/bc2PTzCE
cs_ghuysmans99
Messages postés3982Date d'inscriptionjeudi 14 juillet 2005StatutMembreDernière intervention30 juin 201316 30 mai 2010 à 18:57
Update majeure du code comprenant la validation de la date :
---
/*
# Programme permettant la détermination du jour de la semaine
# d'aprés l'Algorithme de Maurice Kraitchik.
Code original de TheBroyeur - 30/04/2010.
Modifications apportées par :
- Menuki
- LeFauve42
- ghuysmans99
// @ghuysmans99 : ajout
void entreDate(int* jour, int* mois, int* annee)
{
int dateOk;
do
{
printf("Date (JJ MM AAAA) : ");
scanf("%d %d %d",jour,mois,annee);
dateOk = 1;
if (*jour > 31 || *jour < 1) goto nok;
//pas de jours négatifs ou > 31
if (*mois > 12 || *mois < 1) goto nok;
//pas de mois négatifs ou > 12
if (*jour > 29 && *mois == 2) goto nok;
//pas plus de 29 jours en févrierif (!((*annee % 4 0 && *annee % 100 > 0) || (*annee % 400 0)) && (*jour > 28)) goto nok;
//pas plus de 28 jours en février pour les années bisextilesif ((*annee < 1582) || ((*annee 1582) && (*mois < 10)) || ((*annee 1582) && (*mois == 10) && (*jour < 15))) goto nok;
//jours en dessous du 15/10/1582 (date de la réforme grégorienne) invalides car calendrier différent avant cette date
goto ok;
int main()
{
int a; // l'année
int m; // le mois (mais janvier et février sont 13ème et 14ème mois de l'année suivante)
int q ; // le quantième du mois
int j; // le rang du jour de la semaine où 0=samedi, 1=dimanche, etc., 6=vendredi
// @Menuki : ajout
static const char* s_jours[] = {"samedi","dimanche","lundi","mardi","mercredi","jeudi","vendredi"};
printf("La date sous la forme JJ / MM / AAAA :\n\n");
printf("Entrez le jour (JJ): ");
scanf("%d",&j);
printf("Entrez le mois (MM): ");
scanf("%d",&m);
printf("Entrez l'année (AAAA): ");
scanf("%d",&a);
M=m;
cs_ghuysmans99
Messages postés3982Date d'inscriptionjeudi 14 juillet 2005StatutMembreDernière intervention30 juin 201316 26 mai 2010 à 20:25
@adelstyle : Ton 1er code ne ressemble à rien. Et on se fiche complètement d'afficher le mois, l'utilisateur l'a déjà entré par lui-même.
Pour la validation de dates tu dois :
- Vérifier que le jour ne dépasse pas 31.
- Vérifier que le mois ne dépasse pas 12.
Si ces conditions sont remplies, tu peux maintenant vérifier la validité du jour (pas de 31/01 ni de 29/02/2001, par exemple). Tu dois aussi interdire les dates en dessous du 15/10/1582.
Voilà je pense que c'est tout.
Menuki
Messages postés13Date d'inscriptionlundi 10 octobre 2005StatutMembreDernière intervention11 août 2008 26 mai 2010 à 16:12
Je préfère la deuze mais avec la modif' de M. LeFauve42 :
if (m <= 2) {a--;m+=12;}
Par contre, il n'y a toujours pas de vérification des entrées...
ADELSTYLE
Messages postés3Date d'inscriptionmercredi 10 mars 2010StatutMembreDernière intervention30 mai 2010 26 mai 2010 à 16:02
static const char * s_Mois[]={"Janvier","Février","Mars","Avril","Mai","Juin","Juillet","Aout","Septembre","Octobre","Novembre","Décembre"};
printf("Entrez une date sous la forme JJ MM AAAA : ");
scanf("%d %d %d",&j,&m,&a);
thebroyeur
Messages postés7Date d'inscriptiondimanche 10 décembre 2006StatutMembreDernière intervention 8 mai 201012 8 mai 2010 à 11:30
Oui c'est vrai. Je modifie le code tout de suite
cs_ghuysmans99
Messages postés3982Date d'inscriptionjeudi 14 juillet 2005StatutMembreDernière intervention30 juin 201316 5 mai 2010 à 22:34
Non, ça ira très vite si c'est déclaré en static (ce que j'avais oublié de faire). En ASM c'est simplement de l'adressage basé-indexé. Exemple (si eax=jour) : mov edx,[jours+eax*4]
thebroyeur
Messages postés7Date d'inscriptiondimanche 10 décembre 2006StatutMembreDernière intervention 8 mai 201012 5 mai 2010 à 19:22
dsl je continu ma phrase : .... de fonction comme celle-ci et qu'elle sont appelé un grand nombre de fois cela risque de ralentir ton programme.Bien sur dans ce cas, la différence est casi inexistante.
thebroyeur
Messages postés7Date d'inscriptiondimanche 10 décembre 2006StatutMembreDernière intervention 8 mai 201012 5 mai 2010 à 19:16
Ouai c'est vrai que je n'ai pas fait de test sur la date entrée du fait que cette source est une réponse d'une demande que l'on m'a faite. Il est vrai qu'il est indispensable de tester la validité de la date.
Désolé ghuysmans99 si je me suis mal exprimé, ton code est aussi bon que le mien mais seulement si tu a beaucoup de fonction comme celle-ci et qu'elle sont appelé un grand nombre de fois.
Bien vu pour le static et surtout pour le if (m <= 2) {a--;m+=12;} ;) je vais le modifié.
cs_ghuysmans99
Messages postés3982Date d'inscriptionjeudi 14 juillet 2005StatutMembreDernière intervention30 juin 201316 4 mai 2010 à 18:54
Mouais, pas faux pour le static const char* jours[];
Je n'y avais même pas pensé.
Il faudrait aussi penser à valider la date. Là l'utilisateur peut enter 17/343/2010 et le programme ne dira rien :D
LeFauve42
Messages postés239Date d'inscriptionvendredi 20 octobre 2006StatutMembreDernière intervention20 avril 2009 4 mai 2010 à 15:57
> mais si certains comportements sont documentes dans les specificites du language
Il fallait bien sur lire :
"mais si certains comportements sont documentes dans les specifications du language"
LeFauve42
Messages postés239Date d'inscriptionvendredi 20 octobre 2006StatutMembreDernière intervention20 avril 2009 4 mai 2010 à 15:55
>Mais je pense que dans la majorité des cas, il ne faut pas trop s'appuyer sur les
>fonctionnalités spécifiques d'un compilateur en particulier. Rien que pour l'aspect
>portabilité par exemple.
Vaste debat :o)
Je me souviens de mots cles tombes en desuetude, comme "register"(1) par exemple.
L'idee generale est "Le compilateur sait mieux que toi si cette variable doit etre mise dans un registre ou pas".
Apres ca depend ce qu'on entends par "compilateur" :
N'importe qui peut ecrire un compilateur C(2), ca se fait en quelques heures de TP et ca fonctionne pas trop mal pour des programmes simples.
Mais dans la vraie vie, il doit exister environ une demi-douzaine de compilateurs "serieux" et on peut sans problemes esperer qu'ils font bien leur boulot (gcc, visual studio, ...).
Et puis ce genre de comportements (allocation memoire des "variables constantes"(3)) est probablement documente precisement, et pas sujet a interpretation.
Pour dire ca autrement, je suis en faveur de la portabilite mais pas au point de mettre des parentheses partout au cas ou un compilateur exotique ne respecterait pas la precedence des operateurs generalement admise en C.
Bref, c'est bien de ne pas utiliser les specificites non standard d'un compilateur particulier, mais si certains comportements sont documentes dans les specificites du language, pourquoi s'en priver.
J'ai du mal a croire que j'ai ecrit autant sur un bout de code aussi simple (ok, on est un peu parti en "hors topic" vers la fin).
Toutes mes excuses aux lecteurs qui se sont perdu ici et qui ne demandaient qu'un bout de code pour connaitre le jour de la semaine :o)
Je dois commencer a radotter un peu (ca me fait ca quand on parle du bon vieux temps ;o) ).
En tous cas, merci a LeBroyeur pour nous avoir fait partager cet algo tres instructif.
Eric
(1) Et puisque le compilateur se charge d'optimiser tout seul comme un grand, on a ajoute de nouveaux qualifiers comme "volatile"... mais c'est un autre probleme
(2) J'ai bien dit "C", pas "C++". Prevoir un peu plus de temps pour ce dernier language :o)
(3) Oui, je sais, ca n'a pas de sens...
Menuki
Messages postés13Date d'inscriptionlundi 10 octobre 2005StatutMembreDernière intervention11 août 2008 4 mai 2010 à 14:42
A moi de te retourner le compliment, cher ami LeFauve42.
Je te dirais qu'en écrivant mon message, j'y pensais. Mais je dois avouer que la syntaxe des tableaux constants m'a toujours un peu échappé.
Grâce à toi, c'est peut-être rentré dans ma caboche. Je vais en mettre partout à présent!!! ^_^
Pour répondre à ta question, je dirais qu'il n'y a pas de réponse universelle car il n'y a pas qu'un compilateur.
Alors peut-être que certains compilateurs "intelligents" font cette optimisation car, comme tu le précises, il n'y a aucun avantage à faire une copie locale d'une variable constante (en tout cas, je n'en vois pas non plus).
Mais je pense que dans la majorité des cas, il ne faut pas trop s'appuyer sur les fonctionnalités spécifiques d'un compilateur en particulier. Rien que pour l'aspect portabilité par exemple.
Philosophiquement, même si ces fonctionnalités apportent un plus indéniable, je ne suis pas forcément convaincu que ce soit une bonne chose qu'on permette au programmeur d'écrire n'importe quoi en laissant le compilateur corrigé.
Cela me pose toujours un problème de conscience.
Car quoi? Ce n'est qu'une machine après tout! et c'est censé être nous les êtres supérieurs? Non?
LeFauve42
Messages postés239Date d'inscriptionvendredi 20 octobre 2006StatutMembreDernière intervention20 avril 2009 4 mai 2010 à 13:56
Argh... J'ai completement pas pense a "static"... Bien vu Menuki
Mais ta declaration est celle d'un tableau sur objets constants, pas sur un tableau constant :o) (1)
Vu qu'on a un tableau constant d'objets constants, on pourrait avoir:
static const char *const s_jours[]...
Mais ma question premiere se pose toujours (un peu changee) :
Est-ce que le static est necessaire, puisque le tableau et son contenu sont constants, il est probable que le compilateur le traitera comme un "local static" (il n'a aucun interet a ne pas le faire (sauf si j'ai loupe un truc)).
Eric
(1) Vu que je suis completement dyslexique(2), c'est peut-etre le contraire (desole)
(2) Oui, j'ai du googler pour retrouver la bonne orthographe de ce mot :o)
Menuki
Messages postés13Date d'inscriptionlundi 10 octobre 2005StatutMembreDernière intervention11 août 2008 4 mai 2010 à 11:12
J'attendais que Ghuysmans99 réponde pour faire part de mon analyse mais puisqu'on en parle...
Le contenu des chaînes n'a pas à être modifié, donc on peut les passer en const.
Ensuite, il est inutile de recopier le tableau de pointeur sur la pile à chaque appel.
Comme on n'accède au tableau qu'en lecture, on peut le partager entre tous les appels (local static).
Je proposerais donc de déclarer la variable jours en tant que static const char * s_jours[] pour gagner la dizaine d'instruction nécessaire à l'initialisation du tableau.
PS: Bien vu l'histoire du m<=2!
LeFauve42
Messages postés239Date d'inscriptionvendredi 20 octobre 2006StatutMembreDernière intervention20 avril 2009 4 mai 2010 à 10:42
Ca peut etre pratique comme algo.
Mais pour quelles dates est-il valide ?
Je pencherai pour 15/10/1582 => pas de limites mais j'ai du mal a trouver confirmation.
Puisqu'on est dans les optimisations, on peut aussi gagner quelques octets en remplacant
if (m == 1) {a--;m=13;}
if (m == 2) {a--;m=14;}
par :
if (m <= 2) {a--;m+=12;}
La seule difference de taille memoire entre la version originale et celle de ghuysmans99 est le tableau de pointeurs alloue sur la pile (les constantes chaine de caracteres vont etre alouees dans le segment TEXT du code (ou la partie DATA associee selon l'OS) dans les 2 cas).
Ca peut donc avoir quelques repercussions dans quelques cas tres particuliers (code tres recursif), mais honetement j'aurai aussi utilise un tableau (a moins d'etre dans un de ces cas tres particulier).
Le plus efficace serait sans doute de declarer le tableau comme global, afin de ne pas avoir a le recreer sur la pile a chaque appel de la fonction, mais les variables globales, c'est pas trop top pour la maintenance non plus...
A moins qu'en declarant le tableau comme "const" le compilateur se charge d'optimiser ?
Mes cours de compilation commencent un peu a dater :o) mais si quelqu'un a la reponse, je serais curieux de la connaitre.
cs_ghuysmans99
Messages postés3982Date d'inscriptionjeudi 14 juillet 2005StatutMembreDernière intervention30 juin 201316 3 mai 2010 à 19:22
Idem que Menuki : argumente un peu parce que là ça parait un peu léger. 28 octets de pointeurs ce n'est pas beaucoup. Et ce n'est pas parce que le programme grandit que ça prendra plus de place. Je te rappelle quand même que tu prends beaucoup plus de place avec ton switch() car tu appelles printf() à chaque fois. Moi, seulement une fois.
Menuki
Messages postés13Date d'inscriptionlundi 10 octobre 2005StatutMembreDernière intervention11 août 2008 3 mai 2010 à 09:19
Tu pourrais expliquer en quoi l'utilisation d'un tableau augmente l'espace mémoire occupé?
Parce que tes chaînes dans les différents printf, on doit bien les trouver également dans les données du programme, non?
thebroyeur
Messages postés7Date d'inscriptiondimanche 10 décembre 2006StatutMembreDernière intervention 8 mai 201012 2 mai 2010 à 22:48
oui c'est vrai cependant je pense que si tu part dans cette optique lorsque tu va réaliser des programmes assez important tu risque d'avoir des problemes avec ta mémoire. Ton programme est certe plus court en ce qui concerne le code mais il utilise plus d'espace mémoire puisque du introduit un tableau. La qualité d'un programme réside dans sa vitesse d'execution et dans l'espace memoire qu'il occupe ( ne pas oublier un code clair et bien commenté :) )
@++ T=
cs_ghuysmans99
Messages postés3982Date d'inscriptionjeudi 14 juillet 2005StatutMembreDernière intervention30 juin 201316 30 avril 2010 à 18:23
Fonctionne nickel mais on peut faire plus court (21 lignes contre 45 dans ta version) :
#include <stdio.h>
int main()
{
int q; // quantième du mois
int m; // mois où janvier=13 et février=14
int a; // année
int j; // jour de la semaine en partant de samedi
char* jours[] = {"samedi","dimanche","lundi","mardi","mercredi","jeudi","vendredi"};
printf("Entrez une date sous la forme JJ MM AAAA : ");
scanf("%d %d %d",&q,&m,&a);
8 nov. 2010 à 01:08
11 juin 2010 à 21:01
J'ai fait de nouvelles modifs. Au programme : ajout du support de l'Unicode et purification du code. Pour ce petit nettoyage de code, j'ai viré les commentaires différentiels qui ne facilitaient pas la lecture (et pis pour les modifs c'est décrit ici).
Le code est disponible à cette adresse : http://pastebin.com/Zh0WpWmp
3 juin 2010 à 21:05
3 juin 2010 à 09:34
Le problème est que, si tu tolères des exceptions, tu trouveras toujours quelques "tout-fous" pour réclamer d'autres passe-droits.
Au final, tes règles de bonne conduite, censées être établies pour permettre un meilleur échange dans le groupe, ne seront qu'un ramassis de bonnes paroles.
Non, chez nous, cela fait partie de la discipline à laquelle tout le monde s'astreint (volontairement, je précise). Il est vrai que c'est un peu déroutant au début. Un oeil non habitué peut trouver cela moins lisible. Mais après peu de temps, c'est l'inverse qui se produit. Si on ne voit pas les accolades après le if, on est choqué.
Et puis, laisse-moi te raconter une histoire. Un gars de chez nous faisait la forte tête. "Je n'ai qu'une instruction, je ne mets pas d'accolade!". Un jour, il a dû rajouter une deuxième instruction à son if et... il a oublié de rajouter les accolades!
C'est moi qui ait trouvé le bug, pas lui. Comme j'étais choqué à chaque if, ça m'a sauté aux yeux.
Je pense que chez certains, c'est l'orgueil qui parle plus qu'autres choses. Ils pensent prouver leur maîtrise en utilisant toutes les subtilités du langage.
Je ne parle pas de toi. Je ne te connais pas, je ne me permettrais donc pas de te juger.
Certes, c'est bien de savoir ces choses mais si tu les appliques pour qu'au final, ça te complique la vie...
Pour ma part, je suis capable d'écrire du code ultra-condensé mais l'expérience m'a montré que 6 mois plus tard, ce qui était si clair et évident le devient beaucoup moins...
2 juin 2010 à 19:14
# if (*mois > 12 || *mois < 1)
# break;
Beaucoup plus lisible du coup. Mais quand c'est comme ici une série de if avec toujours la même chose dedans, tu peux bien comprendre que ça ne serve à rien dans ce cas-ci.
2 juin 2010 à 09:32
Nous sommes entre programmeurs de bonne compagnie et nous savons nous tenir. :-p
Par contre, j'avoue avoir un peu mal pris le "ça tourne au ridicule".
Quand je suis arrivé dans ma boîte, un gars avait pris cette habitude (dans sa boîte précédente).
J'ai trouvé ça un peu lourd mais je m'y suis plié.
Et je me suis rendu compte que c'était beaucoup plus lisible et qu'il y avait moins de risque d'erreur.
Essaie de relire du code ancien ou lire un code d'un autre : quand la partie action de ton "if" se trouve un coup à la fin de la ligne, un coup sur la ligne en dessous, un coup entre accolades, ça devient vite prise de tête...
Quand tu fais ça au fond d'une usine, avec le client stressé derrière toi parce qu'il perd 10.000€ par minute perdue, tu as envie de tuer le type qui n'a pas suivi la charte pour faire son expert!
Ca fait partie des règles de bonne conduite de notre société et ce n'est pas négociable (notamment avec les stagiaires ;-) ).
Après, en dehors, chacun fait ce qui lui plait mais faut pas se moquer des habitudes des autres. Ils ont peut-être des bonnes raisons de faire ainsi...
1 juin 2010 à 19:03
Menuki aura probablement moins envie de me taper dessus en le voyant (enfin j'espère).
1 juin 2010 à 18:51
Là ça tourne au ridicule :
# if (*mois > 12 || *mois < 1)
# {
# break;
# }
Peut devenir :
# if (*mois > 12 || *mois < 1) break;
1 juin 2010 à 14:48
C'est pas pour une question de performance, c'est pour une question d'hygiène de vie!
C'est écrit partout sur les paquets de biscuit :
"Pour votre santé, éviter de manger sucré, salé et les goto" ;-)
Trève de plaisanterie, comme je l'ai précisé, je n'ai pas envie de rentrer dans la sempiternel gueguerre pro/anti goto. Sans les absoudre totalement, j'estime que, quand je peux faire autrement, je les évite. Et voici un moyen de les éviter (sans perte de performance en plus)...
31 mai 2010 à 18:45
Je vois pas pourquoi on pourrait être contre un goto dans le cas présent.
31 mai 2010 à 10:00
Même si dans certains cas, c'est bien pratique, quand j'ai une autre solution, je préfère les éviter (ne transformons pas ce sujet en guerre pro-contre goto ;-) ).
Dans mes pérégrinations, j'ai découvert une pratique dans des exemples de Microsoft : la "dummy loop".
Donc voici ce que je propose pour la vérification :
void entreDate(int* jour, int* mois, int* annee)
{
for (;;)
{
printf("Date (JJ MM AAAA) : ");
scanf("%d %d %d",jour,mois,annee);
// dummy loop
do
{
if (*jour > 31 || *jour < 1)
{
break;
}
//pas de jours négatifs ou > 31
if (*mois > 12 || *mois < 1)
{
break;
}
//pas de mois négatifs ou > 12
if (*jour > 29 && *mois == 2)
{
break;
}
//pas plus de 29 jours en févrierif (!((*annee % 4 0 && *annee % 100 > 0) || (*annee % 400 0)) && (*jour > 28))
{
break;
}
//pas plus de 28 jours en février pour les années bisextilesif ((*annee < 1582) || ((*annee 1582) && (*mois < 10)) || ((*annee 1582) && (*mois == 10) && (*jour < 15)))
{
break;
}
//jours en dessous du 15/10/1582 (date de la réforme grégorienne) invalides car calendrier différent avant cette date
// si on arrive ici, c'est qu'on a réussi tous les tests, donc la date est OK
return;
}while (false); // fin de la dummy loop
printf("Date invalide.\n");
}
}
Voilà, juste une proposition...
30 mai 2010 à 18:58
http://pastebin.com/bc2PTzCE
30 mai 2010 à 18:57
---
/*
# Programme permettant la détermination du jour de la semaine
# d'aprés l'Algorithme de Maurice Kraitchik.
Code original de TheBroyeur - 30/04/2010.
Modifications apportées par :
- Menuki
- LeFauve42
- ghuysmans99
*/
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
// @ghuysmans99 : ajout
void entreDate(int* jour, int* mois, int* annee)
{
int dateOk;
do
{
printf("Date (JJ MM AAAA) : ");
scanf("%d %d %d",jour,mois,annee);
dateOk = 1;
if (*jour > 31 || *jour < 1) goto nok;
//pas de jours négatifs ou > 31
if (*mois > 12 || *mois < 1) goto nok;
//pas de mois négatifs ou > 12
if (*jour > 29 && *mois == 2) goto nok;
//pas plus de 29 jours en févrierif (!((*annee % 4 0 && *annee % 100 > 0) || (*annee % 400 0)) && (*jour > 28)) goto nok;
//pas plus de 28 jours en février pour les années bisextilesif ((*annee < 1582) || ((*annee 1582) && (*mois < 10)) || ((*annee 1582) && (*mois == 10) && (*jour < 15))) goto nok;
//jours en dessous du 15/10/1582 (date de la réforme grégorienne) invalides car calendrier différent avant cette date
goto ok;
nok:
dateOk = 0;
printf("Date invalide.\n");
ok:
;
} while (dateOk == 0);
}
int main()
{
int a; // l'année
int m; // le mois (mais janvier et février sont 13ème et 14ème mois de l'année suivante)
int q ; // le quantième du mois
int j; // le rang du jour de la semaine où 0=samedi, 1=dimanche, etc., 6=vendredi
// @Menuki : ajout
static const char* s_jours[] = {"samedi","dimanche","lundi","mardi","mercredi","jeudi","vendredi"};
// @ghuysmans99 : modif
entreDate(&q,&m,&a);
// @LeFauve42 : modif
if (m <= 2)
{
a--;
m+=12;
}
j = (q+2*m+((3*(m + 1))/5)+a+(a/4)-(a/100)+(a/400)+2)%7;
// @ghuysmans99 : modif
printf("Ce jour etait un %s.\n", s_jours[j]);
/*printf("\n");
system("pause");*/
return 0;
}
30 mai 2010 à 15:36
29 mai 2010 à 11:44
Merci à tous ceux qui ont fourni des idées
=============== Exemple :) ====================
#include <stdio.h>
#include <stdlib.h>
int main()
{
int j,m,M,a,jour;
static const char * s_jours[]={"Samedi","Dimanche","Lundi","Mardi","Mercredi","Jeudi","Vendredi"};
static const char * s_Mois[]={"Janvier","Février","Mars","Avril","Mai","Juin","Juillet","Aout","Septembre","Octobre","Novembre","Décembre"};
printf("La date sous la forme JJ / MM / AAAA :\n\n");
printf("Entrez le jour (JJ): ");
scanf("%d",&j);
printf("Entrez le mois (MM): ");
scanf("%d",&m);
printf("Entrez l'année (AAAA): ");
scanf("%d",&a);
M=m;
if((M==2 && j>28) && !(a % 4 == 0 && a % 100 != 0 || a %400 == 0)){
printf("\n\nle mois de février [1-28] jour\n\n");}
else{
if(m == 2){a--;m=14;
jour=(j + 2*m + ((3*(m + 1))/5) + a + (a/4) - (a/100) + (a/400) + 2) % 7; a++;}
else if(m == 1) {a--;m=13;
jour=(j + 2*m + ((3*(m + 1))/5) + a + (a/4) - (a/100) + (a/400) + 2) % 7; a++;}
else jour=(j + 2*m + ((3*(m + 1))/5) + a + (a/4) - (a/100) + (a/400) + 2) % 7;
if(j 0 || m 0 || a == 0){
printf("\nErreur JJ/MM/AAA <> 0\n\n");}
else if(j > 31){
printf("\nErreur -> Jour [1-31]\n\n");}
else if(M > 12){
printf("\nErreur -> Mois [1-12]\n\n");}
else if(M == 4 & j >30){
printf("\nErreur -> Mois = 30 jour\n\n");}
else if(M == 6 & j >30){
printf("\nErreur -> Mois = 30 jour\n\n");}
else if(M == 9 & j >30){
printf("\nErreur -> Mois = 30 jour\n\n");}
else if(M == 11 & j >30){
printf("\nErreur -> Mois = 30 jour\n\n");}
else if(M == 2 & j > 29){
printf("\nErreur -> Mois = 29 jour\n\n");}
else {printf("\n%s %02d %s %04d\n\n",s_jours[jour],j,s_Mois[M-1],a);}
}
system("pause");
return 0;
}
26 mai 2010 à 20:25
Pour la validation de dates tu dois :
- Vérifier que le jour ne dépasse pas 31.
- Vérifier que le mois ne dépasse pas 12.
Si ces conditions sont remplies, tu peux maintenant vérifier la validité du jour (pas de 31/01 ni de 29/02/2001, par exemple). Tu dois aussi interdire les dates en dessous du 15/10/1582.
Voilà je pense que c'est tout.
26 mai 2010 à 16:12
if (m <= 2) {a--;m+=12;}
Par contre, il n'y a toujours pas de vérification des entrées...
26 mai 2010 à 16:02
int j,m,M,a,jour;
static const char * s_jours[]={"samedi","dimanche","lundi","mardi","mercredi","jeudi","vendredi"};
printf("Entrez une date sous la forme JJ MM AAAA : ");
scanf("%d %d %d",&j,&m,&a);
M=m;
if(m == 2){a--;m=14;
jour=(j + 2*m + ((3*(m + 1))/5) + a + (a/4) - (a/100) + (a/400) + 2) % 7; a=a+1;}
else if(m == 1) {a--;m=13;
jour=(j + 2*m + ((3*(m + 1))/5) + a + (a/4) - (a/100) + (a/400) + 2) % 7; a=a+1;}
else jour=(j + 2*m + ((3*(m + 1))/5) + a + (a/4) - (a/100) + (a/400) + 2) % 7;
printf("\nLe jour de la semaine correspondant au %02d/%02d/%02d est %s\n.",j,M,a,s_jours[jour]);
====== autre solution: =========
int j,m,M,a,A,jour;
static const char * s_jours[]={"samedi","dimanche","lundi","mardi","mercredi","jeudi","vendredi"};
static const char * s_Mois[]={"Janvier","Février","Mars","Avril","Mai","Juin","Juillet","Aout","Septembre","Octobre","Novembre","Décembre"};
printf("Entrez une date sous la forme JJ MM AAAA : ");
scanf("%d %d %d",&j,&m,&a);
M=m; A=a;
if(m == 2) {a--;m=14;}
if(m == 1) {a--;m=13;}
jour=(j + 2*m + ((3*(m + 1))/5) + a + (a/4) - (a/100) + (a/400) + 2) % 7;
printf("\n %s %02d %s %02d\n.",s_jours[jour],j,s_Mois[M-1],A);
8 mai 2010 à 11:30
5 mai 2010 à 22:34
5 mai 2010 à 19:22
5 mai 2010 à 19:16
Désolé ghuysmans99 si je me suis mal exprimé, ton code est aussi bon que le mien mais seulement si tu a beaucoup de fonction comme celle-ci et qu'elle sont appelé un grand nombre de fois.
Bien vu pour le static et surtout pour le if (m <= 2) {a--;m+=12;} ;) je vais le modifié.
4 mai 2010 à 18:54
Je n'y avais même pas pensé.
Il faudrait aussi penser à valider la date. Là l'utilisateur peut enter 17/343/2010 et le programme ne dira rien :D
4 mai 2010 à 15:57
Il fallait bien sur lire :
"mais si certains comportements sont documentes dans les specifications du language"
4 mai 2010 à 15:55
>fonctionnalités spécifiques d'un compilateur en particulier. Rien que pour l'aspect
>portabilité par exemple.
Vaste debat :o)
Je me souviens de mots cles tombes en desuetude, comme "register"(1) par exemple.
L'idee generale est "Le compilateur sait mieux que toi si cette variable doit etre mise dans un registre ou pas".
Apres ca depend ce qu'on entends par "compilateur" :
N'importe qui peut ecrire un compilateur C(2), ca se fait en quelques heures de TP et ca fonctionne pas trop mal pour des programmes simples.
Mais dans la vraie vie, il doit exister environ une demi-douzaine de compilateurs "serieux" et on peut sans problemes esperer qu'ils font bien leur boulot (gcc, visual studio, ...).
Et puis ce genre de comportements (allocation memoire des "variables constantes"(3)) est probablement documente precisement, et pas sujet a interpretation.
Pour dire ca autrement, je suis en faveur de la portabilite mais pas au point de mettre des parentheses partout au cas ou un compilateur exotique ne respecterait pas la precedence des operateurs generalement admise en C.
Bref, c'est bien de ne pas utiliser les specificites non standard d'un compilateur particulier, mais si certains comportements sont documentes dans les specificites du language, pourquoi s'en priver.
J'ai du mal a croire que j'ai ecrit autant sur un bout de code aussi simple (ok, on est un peu parti en "hors topic" vers la fin).
Toutes mes excuses aux lecteurs qui se sont perdu ici et qui ne demandaient qu'un bout de code pour connaitre le jour de la semaine :o)
Je dois commencer a radotter un peu (ca me fait ca quand on parle du bon vieux temps ;o) ).
En tous cas, merci a LeBroyeur pour nous avoir fait partager cet algo tres instructif.
Eric
(1) Et puisque le compilateur se charge d'optimiser tout seul comme un grand, on a ajoute de nouveaux qualifiers comme "volatile"... mais c'est un autre probleme
(2) J'ai bien dit "C", pas "C++". Prevoir un peu plus de temps pour ce dernier language :o)
(3) Oui, je sais, ca n'a pas de sens...
4 mai 2010 à 14:42
Je te dirais qu'en écrivant mon message, j'y pensais. Mais je dois avouer que la syntaxe des tableaux constants m'a toujours un peu échappé.
Grâce à toi, c'est peut-être rentré dans ma caboche. Je vais en mettre partout à présent!!! ^_^
Pour répondre à ta question, je dirais qu'il n'y a pas de réponse universelle car il n'y a pas qu'un compilateur.
Alors peut-être que certains compilateurs "intelligents" font cette optimisation car, comme tu le précises, il n'y a aucun avantage à faire une copie locale d'une variable constante (en tout cas, je n'en vois pas non plus).
Mais je pense que dans la majorité des cas, il ne faut pas trop s'appuyer sur les fonctionnalités spécifiques d'un compilateur en particulier. Rien que pour l'aspect portabilité par exemple.
Philosophiquement, même si ces fonctionnalités apportent un plus indéniable, je ne suis pas forcément convaincu que ce soit une bonne chose qu'on permette au programmeur d'écrire n'importe quoi en laissant le compilateur corrigé.
Cela me pose toujours un problème de conscience.
Car quoi? Ce n'est qu'une machine après tout! et c'est censé être nous les êtres supérieurs? Non?
4 mai 2010 à 13:56
Mais ta declaration est celle d'un tableau sur objets constants, pas sur un tableau constant :o) (1)
Vu qu'on a un tableau constant d'objets constants, on pourrait avoir:
static const char *const s_jours[]...
Mais ma question premiere se pose toujours (un peu changee) :
Est-ce que le static est necessaire, puisque le tableau et son contenu sont constants, il est probable que le compilateur le traitera comme un "local static" (il n'a aucun interet a ne pas le faire (sauf si j'ai loupe un truc)).
Eric
(1) Vu que je suis completement dyslexique(2), c'est peut-etre le contraire (desole)
(2) Oui, j'ai du googler pour retrouver la bonne orthographe de ce mot :o)
4 mai 2010 à 11:12
Le contenu des chaînes n'a pas à être modifié, donc on peut les passer en const.
Ensuite, il est inutile de recopier le tableau de pointeur sur la pile à chaque appel.
Comme on n'accède au tableau qu'en lecture, on peut le partager entre tous les appels (local static).
Je proposerais donc de déclarer la variable jours en tant que static const char * s_jours[] pour gagner la dizaine d'instruction nécessaire à l'initialisation du tableau.
PS: Bien vu l'histoire du m<=2!
4 mai 2010 à 10:42
Mais pour quelles dates est-il valide ?
Je pencherai pour 15/10/1582 => pas de limites mais j'ai du mal a trouver confirmation.
Puisqu'on est dans les optimisations, on peut aussi gagner quelques octets en remplacant
if (m == 1) {a--;m=13;}
if (m == 2) {a--;m=14;}
par :
if (m <= 2) {a--;m+=12;}
La seule difference de taille memoire entre la version originale et celle de ghuysmans99 est le tableau de pointeurs alloue sur la pile (les constantes chaine de caracteres vont etre alouees dans le segment TEXT du code (ou la partie DATA associee selon l'OS) dans les 2 cas).
Ca peut donc avoir quelques repercussions dans quelques cas tres particuliers (code tres recursif), mais honetement j'aurai aussi utilise un tableau (a moins d'etre dans un de ces cas tres particulier).
Le plus efficace serait sans doute de declarer le tableau comme global, afin de ne pas avoir a le recreer sur la pile a chaque appel de la fonction, mais les variables globales, c'est pas trop top pour la maintenance non plus...
A moins qu'en declarant le tableau comme "const" le compilateur se charge d'optimiser ?
Mes cours de compilation commencent un peu a dater :o) mais si quelqu'un a la reponse, je serais curieux de la connaitre.
3 mai 2010 à 19:22
3 mai 2010 à 09:19
Parce que tes chaînes dans les différents printf, on doit bien les trouver également dans les données du programme, non?
2 mai 2010 à 22:48
@++ T=
30 avril 2010 à 18:23
#include <stdio.h>
int main()
{
int q; // quantième du mois
int m; // mois où janvier=13 et février=14
int a; // année
int j; // jour de la semaine en partant de samedi
char* jours[] = {"samedi","dimanche","lundi","mardi","mercredi","jeudi","vendredi"};
printf("Entrez une date sous la forme JJ MM AAAA : ");
scanf("%d %d %d",&q,&m,&a);
if (m == 1) {a--;m=13;}
if (m == 2) {a--;m=14;}
j = (q + 2*m + ((3*(m + 1))/5) + a + (a/4) - (a/100) + (a/400) + 2) % 7;
printf("\nLe jour de la semaine correspondant au %02d/%02d/%02d est %s.",q,m,a,jours[j]);
return 0;
}