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

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

switch case en c


Sujet :

C

  1. #21
    Membre averti
    Homme Profil pro
    très occupé
    Inscrit en
    Juillet 2014
    Messages
    137
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : très occupé

    Informations forums :
    Inscription : Juillet 2014
    Messages : 137
    Points : 411
    Points
    411
    Par défaut
    Salut Bktero,

    ben quand tu critiques, tu n'y vas pas de main morte :-)

    Citation Envoyé par Bktero Voir le message
    Elle me semble en revanche moins généraliste : comment faire pour dire "si c'est un cadet ou un minime, alors....." ? Tu vas te retrouver à tester le retour de getCategory() contre plusieurs valeurs pour faire ton test alors que tu pourrais appeler mes fonctions qui te renvoie un booléen directement et faire un OU logique entre les retours.
    Il y a un truc que je ne saisis pas dans ton objection, mais pour moi c'est évident que si tu stockes le résultat de get_category() dans une variable, tu peux faire autant de tests que tu veux sans avoir à appeler get_category() de nouveau ou autre chose, et qu'il est plus efficace et moins coûteux de faire ainsi, plutôt d'avoir à appeler de multiples fois des fonctions testant si on est dans une catégorie ou pas.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    	cat = get_category(age);
    	if (cat == CADET || cat == MINIME)
    		printf("Vous avez votre entraînement de 16h00 à 18h00\n");
    C'est lisible grâce à l'enum. En fait, utiliser la variable contenant le membre de l'enum permet même de nous réconcilier avec switch / case pour des tests, si on veux faire ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    	switch (cat) {
    	case CADET:
    	case MINIME:
    		do_things();
    		break;
    	default:
    		do_other_things();
    		break;
    	}
    Citation Envoyé par Bktero Voir le message
    Si pour chaque catégorie, tu souhaites non pas afficher un texte mais faire différentes actions, tu vas faire un tableau de pointeurs de fonctions ; si ailleurs, tu veux faire une autre série d'actions, tu vas faire un second tableaux de pointeurs de fonctions ? Si plusieurs catégories répondent à la même action, tu vas enregistrer plusieurs fois le même pointeur ?
    Je n'allais pas jusque là, mais, oui, on peut faire un array de struct, qui comprend non seulement le texte à afficher, mais aussi les pointeurs vers les fonctions nécessaires selon les actions à exécuter. Le tout en utilisant un index ayant sémantiquement du sens. Je ne vois pas où est le problème, au contraire.

    Mais je ne suis pas un intégriste non plus de tout mettre dans les structures de données. Je ne ferai cela que si de façon pragmatique cela a du sens pour simplifier le développement et sa lisibilité.

    Citation Envoyé par Bktero Voir le message
    Après, je ne suis pas fan de ce genre d'utilisation des énumérations. Pour les limites, tu testes un int contre un type énuméré, certains compilateurs peuvent te générer des warnings, c'est embêtant.
    Selon le standard C89, les membres d'un enum sont un type entier constant nommé, qui sont désignés par le standard comme faisant partie des "integral types" (3.1.2.5), par ailleurs, 3.1.3.3 indique : "An identifier declared as an enumeration constant has type int".

    Il n'y aucune raison de générer un warning. Connais-tu un compilateur qui le fait ?

    En revanche, l'enum permet effectivement de typer la variable qui peut accueillir le résultat de la fonction. Cela a l'avantage que, selon le standard C89, l'affectation d'une valeur à la variable autre qu'un membre de l'énumération générera un warning (A.5 COMMON WARNINGS), ce qui est un "bon warning" que j'aime bien voir, parce qu'il identifie une erreur.

    Un autre avantage de l'enum sur le define est le débogage symbolique des programmes qui l'utilisent.

    Citation Envoyé par Bktero Voir le message
    Enfin, un type énuméré avec un "MAX_AGE" pour connaitre le nombre de valeurs dans l'énumération pour dimensionner un tableau est sans doute pratique, mais (et ce n'est qu'un point de vue personnel) me semble peu rigoureux sémantiquement. Une énumération DAY_OF_WEEK ne se termine pas par "le plus grand des jours", par exemple. Ca peut simplifier la maintenance, mais cela ne devrait pas être visible pour l'utilisateur final du code.
    non, je n'ai pas écrit "MAX_AGE", j'ai écrit "MAX_AGE_CAT" abbréviant en langue anglaise "maximum age categories", ce qui sémantiquement dit bien qu'il s'agit du (nombre) maximum de catégories d'âge. Si le nom ne te plaît pas, tu peux choisir un nom qui te semble plus pertinent (par exemple NB_MAX_AGE_CAT, mais je trouve ma formulation plus directe et non équivoque).

    Cependant, je ne vois pas pourquoi le développeur ne pourrait pas accéder à une information aussi importante que le nombre maximum de constantes, ne serait-ce que pour pouvoir les énumérer dans une boucle, par exemple.

    Citation Envoyé par Bktero Voir le message
    Je ne dis pas que l'approche pas lookup table est mauvaise, elle peut se réléver très utile.
    Ahhh, merci ;-)

    Citation Envoyé par Bktero Voir le message
    (...) j'aurai personnellement préféré encapsuler la récupération du texte dans une fonction const char* getCategoryName(unsigned int age). De plus, l'approche par table n'est pas incompatible avec des if / else. D'ailleurs, au final, tu pourrais coder ta fonction getCategory() avec mes fonctions et on pourrait avoir les 2 mécanismes à disposition.
    L'encapsulation est en théorie une bonne chose. Mais encapsuler tout ce qui bouge est un réflexe que je n'ai pas en tant que programmeur C, et qui complique le code de façon non nécessaire à mon sens. Bien sûr, on peux faire getCategoryName(), mais alors, on s'embarrasse d'une fonction alors que la structure de données contient déjà la réponse. Je ne suis pas partisan de créer une fonction pour une tâche triviale. Plus le code est simple et court, mieux je me porte, et plus je le trouve compréhensible et utilisable.

    Dans le même ordre d'idées, faire 4 fonctions pour faire 4 if me semble être excessif.


    Eks

  2. #22
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2014
    Messages
    42
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2014
    Messages : 42
    Points : 51
    Points
    51
    Par défaut
    Citation Envoyé par Lokicoule Voir le message
    Sinon simplement faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     switch (age)
        {
         case 0 ... 5:
          printf("Vous ne faites parti d'aucune categorie, vous etes trop jeune\n");
          break;
         case 6 ... 7:
          printf("Vous faites parti de la categorie Poussin\n");
          break;
        case 8 ... 9:
          printf("Vous faites parti de la categorie Pupille\n");
          break;
        case 10 ... 11:
          printf("Vous faites parti de la categorie Minime\n");
          break;
        default:
          printf("Vous faites parti de la categorie Cadet\n");
          break;
        }
    ce qui est bien plus élégant que d'énumérer toutes les valeurs possibles que l'age peut prendre
    Je suis d'accord avec toi ta solution est plus élégante mais je viens de la tester (j'utilise Visual Studio 2013 pour compiler) et j'ai des erreurs lors de la compilation

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    Avertissement	1	warning MSB8028: The intermediate directory (Debug\) contains files shared from another project (TP1_Pb3.vcxproj).  This can lead to incorrect clean and rebuild behavior.	C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\Microsoft.CppBuild.targets	388	5	TP1_Pb3_switch
    Erreur	2	error C2143: erreur de syntaxe*: absence de ':' avant '...'	i:\cours\vs 2012\tp1\tp1_pb3_switch\tp1_pb3\tp1_pb3_switch.cpp	23	1	TP1_Pb3_switch
    Erreur	3	error C2143: erreur de syntaxe*: absence de ';' avant '...'	i:\cours\vs 2012\tp1\tp1_pb3_switch\tp1_pb3\tp1_pb3_switch.cpp	23	1	TP1_Pb3_switch
    Erreur	4	error C2143: erreur de syntaxe*: absence de ':' avant '...'	i:\cours\vs 2012\tp1\tp1_pb3_switch\tp1_pb3\tp1_pb3_switch.cpp	26	1	TP1_Pb3_switch
    Erreur	5	error C2143: erreur de syntaxe*: absence de ';' avant '...'	i:\cours\vs 2012\tp1\tp1_pb3_switch\tp1_pb3\tp1_pb3_switch.cpp	26	1	TP1_Pb3_switch
    Erreur	6	error C2143: erreur de syntaxe*: absence de ':' avant '...'	i:\cours\vs 2012\tp1\tp1_pb3_switch\tp1_pb3\tp1_pb3_switch.cpp	29	1	TP1_Pb3_switch
    Erreur	7	error C2143: erreur de syntaxe*: absence de ';' avant '...'	i:\cours\vs 2012\tp1\tp1_pb3_switch\tp1_pb3\tp1_pb3_switch.cpp	29	1	TP1_Pb3_switch
    Erreur	8	error C2143: erreur de syntaxe*: absence de ':' avant '...'	i:\cours\vs 2012\tp1\tp1_pb3_switch\tp1_pb3\tp1_pb3_switch.cpp	32	1	TP1_Pb3_switch
    Erreur	9	error C2143: erreur de syntaxe*: absence de ';' avant '...'	i:\cours\vs 2012\tp1\tp1_pb3_switch\tp1_pb3\tp1_pb3_switch.cpp	32	1	TP1_Pb3_switch
    Après ça vient peut être du fait que en cours on fait du C mais on nous demande d'utiliser Visual Studio qui fait de la prog en c++ du coup peut être que la solution avec un switch case 0 ... 5 ne marche pas en c++ mais uniquement en C

    Sinon j'ai bien vu ta solution avec les if else if else qui est vraiment pas mal et qui est assez courte, merci

    dernière chose, j'ai une petite question de débutant, dans ton billet (http://www.developpez.net/forums/blo...ges-valeurs-c/) pourquoi utilise tu des puts au lieu d'utiliser des printf ? Quel est la différence ? Est ce qu'il est possible d'afficher le contenu d'une variable dans un puts, si non est ce la seule différence entre un printf et un puts ?

    merci

  3. #23
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    @tib44:
    on nous demande d'utiliser Visual Studio qui fait de la prog en c++ du coup peut être que la solution avec un switch case 0 ... 5 ne marche pas en c++ mais uniquement en C
    C'est écriture n'est pas une écriture standard du C, c'est une extension du langage proposé par le compilateur de GCC. Il est donc très possible qu'elle ne soit pas dispo avec Visual Studio (et donc le compilateur qui va avec).

    pourquoi utilise tu des puts au lieu d'utiliser des printf ? Quel est la différence ? Est ce qu'il est possible d'afficher le contenu d'une variable dans un puts, si non est ce la seule différence entre un printf et un puts ?
    puts venir put string : tu ne peux afficher qu'une chaine de caractères (que ce soit puts("bonjour") ou puts(s) à condition que s soit une chaine de caractères), mais tu ne peux pas l'afficher un int par exemple. printf veut dire print format et permet de formater une chaine avant de l'afficher. puts() a l'intérêt de rajouter automatiquement un retour à la ligne. Je l'utilise quasi-systématiquement pour des messages simples à destination de l'utilisateur.

    @Eks
    ben quand tu critiques, tu n'y vas pas de main morte :-)
    Quitte à débattre, autant le faire vraiment.

    De manière générale, je suis d'accord avec ce que tu dis. Je pense qu'on a surtout deux manières de coder, les deux étant valables. Je travaille beaucoup plus en Java (et souvent pour écrire des bibliothèques) qu'en C ces temps-ci et mon raisonnement s'en trouve sûrement changer, j'ai tendance à tout encapsuler et tout cacher. Je préfère proposer des contrats d'API et totalement caché mes structures de données. En fait, exactement l'inverse de la démarche que tu proposes ici

    Je ne ferai cela que si de façon pragmatique cela a du sens pour simplifier le développement et sa lisibilité.
    Tout à fait d'accord avec ça ! Choisir la bonne technique au bon moment. Comme je le disais dans mon précédent poste, je trouve l'écriture avec des fonctions de tests plus naturels (surtout si les tests se complexifient) mais je ne bannie pas une bonne table de correspondance ou des switch / cases bien taillés.

    Je n'allais pas jusque là, mais, oui, on peut faire un array de struct, qui comprend non seulement le texte à afficher, mais aussi les pointeurs vers les fonctions nécessaires selon les actions à exécuter.
    La POO te guette ^^

    Selon le standard C89, les membres d'un enum sont un type entier constant nommé, qui sont désignés par le standard comme faisant partie des "integral types" (3.1.2.5), par ailleurs, 3.1.3.3 indique : "An identifier declared as an enumeration constant has type int".

    Il n'y aucune raison de générer un warning. Connais-tu un compilateur qui le fait ?

    En revanche, l'enum permet effectivement de typer la variable qui peut accueillir le résultat de la fonction. Cela a l'avantage que, selon le standard C89, l'affectation d'une valeur à la variable autre qu'un membre de l'énumération générera un warning (A.5 COMMON WARNINGS), ce qui est un "bon warning" que j'aime bien voir, parce qu'il identifie une erreur.
    Mea culpa, je me suis peut-être trompé entre affectation et comparaison. Faudrait que je vérifie ça (j'ai un code quelque part avec le problème).

    non, je n'ai pas écrit "MAX_AGE", j'ai écrit "MAX_AGE_CAT" abbréviant en langue anglaise "maximum age categories", ce qui sémantiquement dit bien qu'il s'agit du (nombre) maximum de catégories d'âge. Si le nom ne te plaît pas, tu peux choisir un nom qui te semble plus pertinent (par exemple NB_MAX_AGE_CAT, mais je trouve ma formulation plus directe et non équivoque).
    J'ai du mal perso. Et ce n'est pas une question de nom (je l'ai mis au pif mais j'aurais pu l'appeler TOTO ^^), c'est une question de sens : je ne trouve pas que ça fasse partie de l'énumération. Je préférerais avoir une constante séparée.

    Encore une fois, les goûts et les couleurs mais j'aime bien tes arguments, ça fait plaisir de discuter sérieusement

  4. #24
    Rédacteur/Modérateur

    Avatar de Roland Chastain
    Homme Profil pro
    Enseignant
    Inscrit en
    Décembre 2011
    Messages
    4 070
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 4 070
    Points : 15 454
    Points
    15 454
    Billets dans le blog
    9
    Par défaut
    Bonjour !

    Excellente discussion.

    Citation Envoyé par magma² Voir le message
    Cette syntaxe n'est pas permise par tous les compilateurs.
    Avec le vieux Borland C++ 5.5 non plus, ça ne passe pas.

    Le mieux c'est de se mettre au Pascal.

    Code delphi : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
      case age of
        0..5  : WriteLn('Vous ne faites partie d''aucune categorie, vous etes trop jeune');
        6, 7  : WriteLn('Vous faites partie de la categorie Poussin');
        8, 9  : WriteLn('Vous faites partie de la categorie Pupille');
        10, 11: WriteLn('Vous faites partie de la categorie Minime');
        else    WriteLn('Vous faites partie de la categorie Cadet');
      end;
    Mon site personnel consacré à MSEide+MSEgui : msegui.net

  5. #25
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Roland Chastain Voir le message
    Le mieux c'est de se mettre au Pascal.
    Ou à Python ! Ah ben non mince y a pas switch / case en Python....

    Citation Envoyé par Bktero Voir le message
    Je ne dis pas que l'approche pas lookup table est mauvaise, elle peut se réléver très utile.
    Je viens d'ailleurs à l'instant d'utiliser une telle table en C (pour faire des correspondantes d'identifiants)

  6. #26
    Membre averti
    Homme Profil pro
    très occupé
    Inscrit en
    Juillet 2014
    Messages
    137
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : très occupé

    Informations forums :
    Inscription : Juillet 2014
    Messages : 137
    Points : 411
    Points
    411
    Par défaut
    @Bktero: merci pour cet échange argumenté et tes propos éclairés, c'est vrai qu'au final, ce sont des styles de programmation différents, l'un étant plus proche du C traditionnel, l'autre des pratiques objet.

    Citation Envoyé par Bktero Voir le message
    (...)
    Je viens d'ailleurs à l'instant d'utiliser une telle table en C (pour faire des correspondantes d'identifiants)



    Eks,
    activiste du FLODAMO :-D

  7. #27
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 629
    Points : 10 554
    Points
    10 554
    Par défaut
    Citation Envoyé par -Eks- Voir le message
    Je n'allais pas jusque là, mais, oui, on peut faire un array de struct, qui comprend non seulement le texte à afficher, mais aussi les pointeurs vers les fonctions nécessaires selon les actions à exécuter. Le tout en utilisant un index ayant sémantiquement du sens. Je ne vois pas où est le problème, au contraire.
    Citation Envoyé par Bktero Voir le message
    La POO te guette ^^
    C'est overkill : c'est une technique qui permet de faire des machines à états en C un peu objet, parce que les switch/ case c'est mignon mais cela devient vite illisible et difficilement maintenable.

    Et moi j'ai toujours réussi à avoir un algo de manipulation de la machine (*) en très peu de lignes et fixe dans le temps

    * -> dans l'exemple, c'est tout le corps de la boucle for avec des tests qu'on peut supprimer parce qu'on est sûr que notre machine est calée ... sauf éventuellement en développement


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    #include<stdio.h>
     
     
    typedef enum {
        TOO_YOUNG = 0, POUSSIN, PUPILLE, MINIME, CADET, TOO_OLD, NB_TYPE, NO_CAT
    } CATEGORY_TYPE ;
     
     
    typedef struct s_Category {
        const char* (*get_name) ();
        const char* (*other_str) ();
     
        unsigned char (*test_age) (unsigned char /*age*/);
     
        CATEGORY_TYPE next_category;
    } Category;
     
     
    const char* Minima_str() { return "vous etes trop jeune"; }
    const char* Maxima_str() { return "vous etes trop vieux"; }
     
    const char* get_Poussin() { return "Poussin"; }
    const char* get_Pupille() { return "Pupille"; }
    const char* get_Minime()  { return "Minime"; }
    const char* get_Cadet()   { return "Cadet"; }
     
    unsigned char test_Minima(unsigned char age)  { return (age < 6); }
    unsigned char test_Poussin(unsigned char age) { return ((age == 6)  || (age == 7));  }
    unsigned char test_Pupille(unsigned char age) { return ((age == 8)  || (age == 9));  }
    unsigned char test_Minime(unsigned char age)  { return ((age == 10) || (age == 11)); }
    unsigned char test_Cadet(unsigned char age)   { return ((age >= 12) && (age <= 20)); }
    unsigned char test_Maxima(unsigned char age)  { return 1; /* or return (age > 20);*/ }
     
     
    int main(int argc, char* argv[])
    {
        Category list_categories[NB_TYPE];
     
    //  TOO_YOUNG
        list_categories[TOO_YOUNG].get_name  = NULL;
        list_categories[TOO_YOUNG].other_str = Minima_str;
        list_categories[TOO_YOUNG].test_age  = test_Minima;
        list_categories[TOO_YOUNG].next_category = POUSSIN;
     
    //  POUSSIN
        list_categories[POUSSIN].get_name  = get_Poussin;
        list_categories[POUSSIN].other_str = NULL;
        list_categories[POUSSIN].test_age  = test_Poussin;
        list_categories[POUSSIN].next_category = PUPILLE;
     
    //  PUPILLE
        list_categories[PUPILLE].get_name  = get_Pupille;
        list_categories[PUPILLE].other_str = NULL;
        list_categories[PUPILLE].test_age  = test_Pupille;
        list_categories[PUPILLE].next_category = MINIME;
     
    //  MINIME
        list_categories[MINIME].get_name  = get_Minime;
        list_categories[MINIME].other_str = NULL;
        list_categories[MINIME].test_age  = test_Minime;
        list_categories[MINIME].next_category = CADET;
     
    //  CADET
        list_categories[CADET].get_name  = get_Cadet;
        list_categories[CADET].other_str = NULL;
        list_categories[CADET].test_age  = test_Cadet;
        list_categories[CADET].next_category = TOO_OLD;
     
    //  TOO_OLD
        list_categories[TOO_OLD].get_name  = NULL;
        list_categories[TOO_OLD].other_str = Maxima_str;
        list_categories[TOO_OLD].test_age  = test_Maxima;
        list_categories[TOO_OLD].next_category = NO_CAT;
     
     
    //  Test
        CATEGORY_TYPE current_category = TOO_YOUNG;
        unsigned char age = 1;
     
        for(; age <= 22; ++age, current_category = TOO_YOUNG) {
            while((current_category != NO_CAT)  && !(list_categories[current_category].test_age(age))) {
    // or   while((current_category <  NB_TYPE) && !(list_categories[current_category].test_age(age))) {
                current_category = list_categories[current_category].next_category;
            }
     
    //      if (current_category != NO_CAT) {
                if (list_categories[current_category].get_name != NULL) {
                    printf("Age %2d: Vous faites parti de la categorie %s\n", age, list_categories[current_category].get_name());
                } else if (list_categories[current_category].other_str != NULL) {
                    printf("Age %2d: %s\n", age, list_categories[current_category].other_str());
                }
    //      }
        }
     
        return 0;
    }

  8. #28
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 149
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 149
    Points : 28 116
    Points
    28 116
    Par défaut
    Bonjour,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    #include<stdio.h>
     
     
    typedef enum {
        TOO_YOUNG = 0, POUSSIN, PUPILLE, MINIME, CADET, TOO_OLD, NB_TYPE, NO_CAT
    } CATEGORY_TYPE ;
     
     
    typedef struct s_Category {
        const char* (*get_name) ();
        const char* (*other_str) ();
     
        unsigned char (*test_age) (unsigned char /*age*/);
     
        CATEGORY_TYPE next_category;
    } Category;
     
     
    const char* Minima_str() { return "vous etes trop jeune"; }
    const char* Maxima_str() { return "vous etes trop vieux"; }
     
    const char* get_Poussin() { return "Poussin"; }
    const char* get_Pupille() { return "Pupille"; }
    const char* get_Minime()  { return "Minime"; }
    const char* get_Cadet()   { return "Cadet"; }
     
    unsigned char test_Minima(unsigned char age)  { return (age < 6); }
    unsigned char test_Poussin(unsigned char age) { return ((age == 6)  || (age == 7));  }
    unsigned char test_Pupille(unsigned char age) { return ((age == 8)  || (age == 9));  }
    unsigned char test_Minime(unsigned char age)  { return ((age == 10) || (age == 11)); }
    unsigned char test_Cadet(unsigned char age)   { return ((age >= 12) && (age <= 20)); }
    unsigned char test_Maxima(unsigned char age)  { return 1; /* or return (age > 20);*/ }
     
     
    int main(int argc, char* argv[])
    {
        Category list_categories[NB_TYPE];
     
    //  TOO_YOUNG
        list_categories[TOO_YOUNG].get_name  = NULL;
        list_categories[TOO_YOUNG].other_str = Minima_str;
        list_categories[TOO_YOUNG].test_age  = test_Minima;
        list_categories[TOO_YOUNG].next_category = POUSSIN;
     
    //  POUSSIN
        list_categories[POUSSIN].get_name  = get_Poussin;
        list_categories[POUSSIN].other_str = NULL;
        list_categories[POUSSIN].test_age  = test_Poussin;
        list_categories[POUSSIN].next_category = PUPILLE;
     
    //  PUPILLE
        list_categories[PUPILLE].get_name  = get_Pupille;
        list_categories[PUPILLE].other_str = NULL;
        list_categories[PUPILLE].test_age  = test_Pupille;
        list_categories[PUPILLE].next_category = MINIME;
     
    //  MINIME
        list_categories[MINIME].get_name  = get_Minime;
        list_categories[MINIME].other_str = NULL;
        list_categories[MINIME].test_age  = test_Minime;
        list_categories[MINIME].next_category = CADET;
     
    //  CADET
        list_categories[CADET].get_name  = get_Cadet;
        list_categories[CADET].other_str = NULL;
        list_categories[CADET].test_age  = test_Cadet;
        list_categories[CADET].next_category = TOO_OLD;
     
    //  TOO_OLD
        list_categories[TOO_OLD].get_name  = NULL;
        list_categories[TOO_OLD].other_str = Maxima_str;
        list_categories[TOO_OLD].test_age  = test_Maxima;
        list_categories[TOO_OLD].next_category = NO_CAT;
     
     
    //  Test
        CATEGORY_TYPE current_category = TOO_YOUNG;
        unsigned char age = 1;
     
        for(; age <= 22; ++age, current_category = TOO_YOUNG) {
            while((current_category != NO_CAT)  && !(list_categories[current_category].test_age(age))) {
    // or   while((current_category <  NB_TYPE) && !(list_categories[current_category].test_age(age))) {
                current_category = list_categories[current_category].next_category;
            }
     
    //      if (current_category != NO_CAT) {
                if (list_categories[current_category].get_name != NULL) {
                    printf("Age %2d: Vous faites parti de la categorie %s\n", age, list_categories[current_category].get_name());
                } else if (list_categories[current_category].other_str != NULL) {
                    printf("Age %2d: %s\n", age, list_categories[current_category].other_str());
                }
    //      }
        }
     
        return 0;
    }
    Attention tout de même à l'utilisation des pointeurs de fonction en C : ce code est simple, et tient sur quelques dizaines de lignes, c'est donc encore lisible, et on peut assez facilement retrouver quelle fonction fait quoi.

    Mai ce même genre de code dans 10 fichiers de plusieurs centaines de lignes, et on est très vite perdu. Et vu qu'il n'existe pas un IDE capable de suivre les pointeurs de fonction (du moins pas à ma connaissance), tu es bien embêté lorsque tu cherches à suivre le code, et à rentrer dans une fonction.
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  9. #29
    Membre averti
    Homme Profil pro
    très occupé
    Inscrit en
    Juillet 2014
    Messages
    137
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : très occupé

    Informations forums :
    Inscription : Juillet 2014
    Messages : 137
    Points : 411
    Points
    411
    Par défaut
    @gangsoleil :

    Citation Envoyé par gangsoleil Voir le message
    (...)
    Attention tout de même à l'utilisation des pointeurs de fonction en C : ce code est simple, et tient sur quelques dizaines de lignes, c'est donc encore lisible, et on peut assez facilement retrouver quelle fonction fait quoi.

    Mai ce même genre de code dans 10 fichiers de plusieurs centaines de lignes, et on est très vite perdu.
    Ce n'est pas faux.

    Cependant, c'est aussi une question de présentation et de familiarité avec cette approche d'implémentation.

    foetus propose une implémentation de machines à états utilisant cette technique d'indexation de pointeurs vers des fonctions, qui, comme il le dit, présente l'intérêt d'éviter des switch / case ingérables.

    Les machines à états, c'est encore autre chose. Leur usage n'est pas fréquent mais lorsque le problème à traiter s'y prête (ce n'est pas forcément le cas de l'application de la personne ayant initialement posté, ce qui ne retire rien à la qualité de l'exemple donné par foetus), c'est un outil remarquable. Et effectivement l'indexation des données propres aux différents états, avec les pointeurs vers les fonctions permettant de passer d'un état à un autre est une application élégante de la technique de l'usage de tables aux machines à états.

    Citation Envoyé par gangsoleil Voir le message
    Et vu qu'il n'existe pas un IDE capable de suivre les pointeurs de fonction (du moins pas à ma connaissance), tu es bien embêté lorsque tu cherches à suivre le code, et à rentrer dans une fonction.
    Si tu veux parler d'une session de débogage, cela ne pose aucun problème à gdb (et aux EDI qui l'utilisent), de suivre l'exécution du code.

    Le problème n'est pas là.

    @gangsoleil et @foetus
    A mon sens, il faut pas séparer la déclaration des structures de données de l'initialisation, car le but de la technique est de regrouper tout cela.

    Donc, plutôt que de faire tous les list_categories[TOO_YOUNG].get_name = NULL; etc. dans le code, j’initialiserai le contenu du tableau de structures avec sa déclaration, en faisant usage de l'enum pour la lisibilité, ce qui, en C89 peut donner ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    struct s_Category list_categories[NB_TYPE] = {
    	/* data order: get_name, other_str, test_age, next_category */
    	[TOO_YOUNG]
    	{
    		/* get_name */		NULL,
    		/* other_str */		Minima_str,
    		/* test_age */		test_Minima,
    		/* next_category */	POUSSIN
    	},
    	[POUSSIN]
    	{
    		/* get_name */		get_Poussin,
    		/* other_str */		NULL,
    		/* test_age */		test_Poussin,
    		/* next_category */	PUPILLE
    	},
    	[PUPILLE]
    	{
    		/* get_name */		get_Pupille,
    		/* other_str */		NULL,
    		/* test_age */		test_Pupille,
    		/* next_category */	MINIME
    	},
    	[MINIME]
    	{
    		/* get_name */		get_Minime,
    		/* other_str */		NULL,
    		/* test_age */		test_Minime,
    		/* next_category */	CADET
    	},
    	[CADET]
    	{
    		/* get_name */		get_Cadet,
    		/* other_str */		NULL,
    		/* test_age */		test_Cadet,
    		/* next_category */	TOO_OLD
    	},
    	[TOO_OLD]
    	{
    		/* get_name */		NULL,
    		/* other_str */		Maxima_str,
    		/* test_age */		test_Maxima,
    		/* next_category */	NO_CAT
    	}
    };
    En C99, on pourrait aussi nommer les champs. En C89, on peut mettre des commentaires, comme ci-dessus (ce qui n'est pas moins lisible). L'insertion de l'index et de la valeur (ex : [TOO_YOUNG]) a plusieurs vertus : faciliter la lisibilité, et permettre l'évolution de la structure de données. Si j'ajoute un élément à l'enum (ou même si je l'insère), je n'ai pas à ré-écrire ma structure de données, tout reste correctement affecté à l'initialisation.

    @foetus : du coup, non seulement tu peux supprimer les for de ton main, mais aussi toutes les initialisations :-)

    @gangsoleil : Le cas de la machine à états est extrême dans l'utilisation de cette technique. Les problèmes peuvent venir du fait que lorsque les actions à effectuer en fonction des états n'ont pas été correctement identifiées, tu te retrouves avec un état incorrect, et tu dois suivre la chronologie du passage d'un état à un autre pour comprendre d'où vient l'erreur.

    Ces difficultés de débogage sont, à mon sens, propres à la mise en oeuvre de la machine à états et non pas à celle de l'usage de pointeurs de fonctions (ce serait pire avec des switch / cases).

    Pour déboguer (ou même en production) de genre d'implémentations, il peut être utile de conserver un log de la chronologie des états et actions, pour être capable de retracer ses pas plus facilement.


    Eks

  10. #30
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 629
    Points : 10 554
    Points
    10 554
    Par défaut
    Citation Envoyé par -Eks- Voir le message
    foetus propose une implémentation de machines à états utilisant cette technique d'indexation de pointeurs vers des fonctions, qui, comme il le dit, présente l'intérêt d'éviter des switch / case ingérables.
    Un autre problème des switch/ case est le fait de ne pas pouvoir créer de variables dans les case (il faut les sortir).
    Édit: Il faut faire des blocks (Bktero l'a fait remarquer)

    Et il y a éventuellement aussi l'indentation (surtout avec des cases bien remplis), à moins que tu indentes les cases au niveau de ton switch.


    Citation Envoyé par -Eks- Voir le message
    Et effectivement l'indexation des données propres aux différents états, avec les pointeurs vers les fonctions permettant de passer d'un état à un autre est une application élégante de la technique de l'usage de tables aux machines à états.
    C'est vrai que mon exemple regroupe 2-3 techniques:
    • L'enum est trié
    • Un état sentinelle
    • Le nombre de valeurs (qui est variable et automatique) en créant une valeur énumérée après toutes les valeurs énumérées,
    • Une valeur énumérée NULL, que l'on peut tester de 2 façons de par sa position
    • Des états ayant une petite taille. Parce que on pouvait mettre l'age minimum et l'age maximal dans l'état et passer par une fonction de test générique, mais cela rajoute au moins soit 2 (char) soit 4 (short) soit 8 (int) octets



    Citation Envoyé par -Eks- Voir le message
    @gangsoleil et @foetus
    A mon sens, il faut pas séparer la déclaration des structures de données de l'initialisation, car le but de la technique est de regrouper tout cela.
    Je suis un fan de macros, surtout si ce ne sont que des affectations on fait une macro pour faire une initialisation en 1 ligne.
    Mais ta solution est encore plus propre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    #define INIT_STATE(state, next_state, func_get_name, func_other_str, func_test_age) \
        list_categories[state].get_name  = func_get_name; \
        list_categories[state].other_str = func_other_str; \
        list_categories[state].test_age  = func_test_age; \
        list_categories[state].next_category = next_state;


    Citation Envoyé par -Eks- Voir le message
    @foetus : du coup, non seulement tu peux supprimer les for de ton main
    Mon for sert à tester ma machine à états, de la même manière qu'on teste un switch/ case, avec des ages compris entre 1 et 22 ans

  11. #31
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 149
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 149
    Points : 28 116
    Points
    28 116
    Par défaut
    Citation Envoyé par -Eks- Voir le message
    Si tu veux parler d'une session de débogage, cela ne pose aucun problème à gdb (et aux EDI qui l'utilisent), de suivre l'exécution du code.
    Non, je parle de reprendre ce genre de code au bout de 6 mois ou un an, que 3 personnes soient passées dessus, et que tu te retrouves dans un fichier à lire ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (strcmp (list_categories[2].get_name(), "mon_nom") == 0)
    dans ce cas, tu ne peux pas simplement "cliquer" sur la focntion get_name pour savoir ce qu'elle fait : tu dois aller voir dans un fichier d'en-tete sur quoi pointe list_categories[2], puis chercher à la main dans tout le code où est la fonction dont tu viens de trouver le nom.

    C'est ce que je viens de faire sur un bout de code, et je peux t'assurer que s'il est vrai que la manière est jolie, elle est vraiment pénible à débugger lorsqu'on dépasse quelques centaines de lignes de code.
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  12. #32
    Membre expérimenté

    Homme Profil pro
    Collégien
    Inscrit en
    Juillet 2010
    Messages
    545
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Afghanistan

    Informations professionnelles :
    Activité : Collégien

    Informations forums :
    Inscription : Juillet 2010
    Messages : 545
    Points : 1 431
    Points
    1 431
    Par défaut
    Bonjour!!

    Permettez-moi de rajouter mon grain de sable, et de proposer une solution (en Franglais..)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     
     typedef enum
     {
        TROP_JEUNE = 0,
        POUSSIN,
        PUPILLE,
        MINIME,
        CADET,
        TROP_VIEUX,
        N_CATEGORIES,
     }category_t
     
     static const char* const catNames[N_CATEGORIES] = { "trop jeune", "poussin",
    		"pupille", "minime", "cadet", "trop vieux"};
     
     
    const char * category_2Str(category_t cat)
    {  /* les type enumérés sont non signés..*/
        return cat<N_CATEGORIES?catNames[cat]:catNames[TROP_VIEUX];
    }
     
    category_t category_from_age(int age)
    {
        return age<6?TROP_JEUNE:
    	    age<8?POUSSIN:
    	    age<10?PUPILLE:
    	    age<12?MINIME:
    	    age<20?CADET:TROP_VIEUX;
    }
     
    int main(void) {
    	int age = 0;
    	puts("Age ?");
    	/* scanf pas terrible mais simple pour cet exemple */
    	scanf("%d", &age);
     
    	printf("Il a %d ans ?\n", age);
    	printf("Cet âge correspond à la catégorie : %s\n",
    			category_2Str(category_from_age(age));
     
    	return 0;
    }

  13. #33
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 684
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 684
    Points : 30 973
    Points
    30 973
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par mith06 Voir le message
    Permettez-moi de rajouter mon grain de sable, et de proposer une solution (en Franglais..)
    Bonjour

    Ca ne me plait pas trop. Parce que le jour où tu veux insérer une catégorie supplémentaire entre "pupille" et "minime" te faut modifier 3 fois ton code à 3 endroits différents. Et pareil avec tous ces pointeurs de fonctions. Certes c'est la super éclate avec les get_Pupille() et get_Cadet() mais question évolutivité c'est pas simple (déjà rien qu'à relire...)

    Perso j'aime bien tout centraliser à un seul endroit: la structure

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    #include <stdio.h>
    #include <string.h>
     
    typedef struct {
    	unsigned short age;
    	char *libelle;
    } t_categorie;
     
    int main()
    {
    	t_categorie tabCategories[]={
    		{5, "trop jeune"},
    		{7, "poussin"},
    		{9, "pupille"},
    		{11, "minime"},
    		{18, "cadet"},
    		{0, NULL},
    	};
    	t_categorie *pt_cat;
    	int age;
     
    	fputs("Entrez l'age :", stdout);
    	scanf("%d", &age);
     
    	for (pt_cat=tabCategories; pt_cat->libelle != NULL; pt_cat++)
    	{
    		if (age <= pt_cat->age)
    		{
    			printf("Sa catégorie est %s\n", pt_cat->libelle);
    			break;
    		}
    	}
    	if (pt_cat->libelle == NULL)
    		printf("L'age %d n'entre pas dans les critères\n", age);
    }

    Et voilà. Celui qui veut rajouter la catégorie "vieillard sénile" n'a qu'à rajouter la ligne qui va bien. Ensuite bien entendu on peut affiner la gestion en rajoutant dans la structure une borne min et une borne max mais c'est du détail.

    Euh oui je crois que question switch/case le sujet a un peu dérapé
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  14. #34
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 629
    Points : 10 554
    Points
    10 554
    Par défaut
    Citation Envoyé par gangsoleil Voir le message
    Non, je parle de reprendre ce genre de code au bout de 6 mois ou un an, que 3 personnes soient passées dessus, et que tu te retrouves dans un fichier à lire ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (strcmp (list_categories[2].get_name(), "mon_nom") == 0)
    Même si tu as raison, mais avec une machine à états en théorie, tu dois conserver l'état courant et passer soit par un algo soit par un contexte pour changer d'état/ manipuler les états.

    Donc tu ne devrais jamais trouver cela dans ton code

    Par exemple, je faisais une machine à états pour coder l'enchaînement de mes fenêtres dans une application mobile.
    Et j'avais presque toujours 2 événements par écrans/ états: suivant et précédent [et éventuellement menu]


    Citation Envoyé par Sve@r Voir le message
    Certes c'est la super éclate avec les get_Pupille() et get_Cadet() mais question évolutivité c'est pas simple (déjà rien qu'à relire...)


    Pour la relecture je suis comme -Eks- : en fonction du projet (de par sa taille et sa complexité) c'est souvent difficile d'avoir du code [très] lisible, même s'il y a pleins de pratiques pour y arriver ... plus ou moins.


    Citation Envoyé par Sve@r Voir le message
    Euh oui je crois que question switch/case le sujet a un peu dérapé
    Pas tant que cela: parce que, aussi simple soit le switch/ case:
    • à l'utilisation ce n'est pas évident de faire des intervalles
    • on ne peut pas créer de variables à l'intérieur des case. Il faut faire des blocks (Bktero l'a fait remarquer)
    • cela devient vite illisible, et donc difficilement maintenable


    D'ailleurs je suis un fan des parsers codés avec des switch/ case imbriqués

    Et on a brossé un peu toutes les possibilités:
    • les extensions du compilateur
    • les if/ else: simple ou avec appel de fonctions/ procédures
    • les machines à états
    • ton code qui est une machine à états ultra-simplifiée: pas de valeurs énumérées, pas de changement de comportements (pointeurs de fonctions), 1 seul événement de prévu (tu dois rajouter un if pour gérer l'absence de catégorie)

  15. #35
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    on ne peut pas créer de variables à l'intérieur des case
    C'est-à-dire ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #include <stdio.h>
     
    int main(void)
    {
      int a = 2;
      switch(a)
      {    
        case 2:
        {
          int b = 5;      
          puts("a vaut 2");
          printf("a + b = %d\n", a + b);
        }
     
        default:
        {
          int b = 3;
          puts("a n vaut pas 2");
          printf("a + b = %d\n", a + b);
        }
      }
    }
    $ c99 variable_in_case.c 
    $ ./a.out 
    a vaut 2
    a + b = 7
    a n vaut pas 2
    a + b = 5
    

  16. #36
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 684
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 684
    Points : 30 973
    Points
    30 973
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Bktero Voir le message
    a ne vaut pas 2
    a + b = 5
    
    Ben si, a vaut bel et bien 2 !!! En plus puisque b vaut 3 et que a+b vaut 5 alors... (résolution d'équation du premier degré à une inconnue...)

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    default:
        {
          int b = 3;
          puts("a vaut peut-être 2, peut-être pas, c'est la faute à pas de break dans le cas précédent... ;)");
          printf("a + b = %d\n", a + b);
        }
      }
    }
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  17. #37
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    C'est bien tu réfléchis vite
    Je m'étais tâté à mettre un commentaire pour dire que j'étais conscient qu'il n'y avait pas de break, mais je me suis dit que j'allais voir qui tomberait dans le panneau les 2 pieds d'un coup...

    C'était juste pour montrer que tu peux déclarer des variables dans des cases, que plusieurs pleuvent déclarer la même variable, et que passer dans plusieurs cases ne posent pas de problème.

  18. #38
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 629
    Points : 10 554
    Points
    10 554
    Par défaut
    Citation Envoyé par Bktero Voir le message
    C'était juste pour montrer que tu peux déclarer des variables dans des cases, que plusieurs pleuvent déclarer la même variable, et que passer dans plusieurs cases ne posent pas de problème.
    J'ai mis à jour mes messages

    Et c'est peut-être pour cela que c'est un truc que j'avais oublié : faire un block dans un case dans un switch .
    L'indentation devient très rigoureuse: dans ton exemple 16 lignes pour 7 lignes de code effectif pour gérer 2 cas (et encore tu n'as pas breaker)

    Oui les cases continus sont un petit "plus", mais qu'il faut 1) faire attention (si on n'en veut pas) 2) avoir la possibilité de les utiliser

Discussions similaires

  1. [Language]Probleme de switch case
    Par nana1 dans le forum Langage
    Réponses: 20
    Dernier message: 17/11/2005, 00h49
  2. switch case pour deux variable en meme temps
    Par petitours dans le forum C
    Réponses: 3
    Dernier message: 06/11/2005, 19h20
  3. [Tableaux] Problème avec Switch case
    Par philippef dans le forum Langage
    Réponses: 4
    Dernier message: 07/09/2005, 16h37
  4. probleme gestion condition switch - case
    Par DarkMax dans le forum Langage
    Réponses: 5
    Dernier message: 07/09/2005, 14h25
  5. [Language] aide sur les switch case
    Par pouss dans le forum Langage
    Réponses: 3
    Dernier message: 05/04/2005, 11h34

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo