begin process at 2012 02 12 10:52:30
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

Astuces

 > SWITCH DE STRINGS (C++)

SWITCH DE STRINGS (C++)


 Information sur la source

Note :
Aucune note
Catégorie :Astuces Classé sous :switch, strings, char, strcmp, arguments Niveau :Débutant Date de création :15/08/2006 Date de mise à jour :15/08/2006 15:49:29 Vu :27 538

Auteur : ordiman85

Ecrire un message privé
Site perso
Ce membre participe au partage de revenus publicitaires
Commentaire sur cette source (17)
Ajouter un commentaire et/ou une note


 Description

J'ai eu un jour une idée pour "switcher" les strings, ce qui est impossible en c ou c++. Faire des strcmp à tout bout de champ, ça ne m'intéressait pas pour créer un code bien espacé et compréhensible.

Pour me rapprocher des switchs, j'ai décider de faire une fonction à arguments illimités qui renvoie la position de l'argument qui répond au "switch". La fonction s_() effectue tous les strcmp un par un avant que la valeur renvoyée passe au switch.

Voilà ce que ça donne concrètement :

Source

  • /********************
  • * Switch de string *
  • * par ordiman85 *
  • ********************/
  • #include <conio.h>
  • #include <stdio.h>
  • #include <string.h>
  • // char* str est la string à "switcher"
  • // IMPORTANT !! Mettre 0 comme dernier argument !
  • #ifdef __cplusplus
  • // Fonction pour C++
  • unsigned int s_(char* str, ...)
  • {
  • unsigned int i = 0;
  • while (*(++i+&str) != 0)
  • if (strcmp(str, (char*)*(&str+i)) == 0)
  • return i;
  • return 0;
  • }
  • #else
  • // Fonction pour le langage C
  • unsigned int s_(char* str, char* cmp[])
  • {
  • unsigned int i = 0;
  • while (cmp[i] != 0) {
  • if (strcmp(str, cmp[i]) == 0)
  • return i+1;
  • i++;
  • }
  • return 0;
  • }
  • #endif
  • // Fonction principale
  • int main()
  • {
  • printf("Test du switch de strings :\r\n");
  • // La string à tester est "switch", sa position est 4
  • char* String = "switch";
  • // On récupère un entier qui correspond à la position de la string identifiée
  • // Méthode 1 (C++)
  • #ifdef __cplusplus
  • unsigned int id = s_(String, "Hello", "world", "!", "switch", "strings", 0);
  • #else // Méthode 2 (C)
  • char* comp[] = {"Hello", "world", "!", "switch", "strings", 0};
  • unsigned int id = s_(String, comp);
  • #endif
  • // Le switch
  • switch (id)
  • {
  • case 1: // "Hello"
  • printf("%d. Hello", id);
  • break;
  • case 2: // "world"
  • printf("%d. world", id);
  • break;
  • case 3: // "!"
  • printf("%d. !", id);
  • break;
  • case 4: // "switch"
  • printf("%d. switch", id);
  • break;
  • case 5: // "strings"
  • printf("%d. strings", id);
  • break;
  • default: // Pas identifié, id = 0
  • printf("Pas dans la liste (%d)", id);
  • break;
  • }
  • // Pause et fin
  • getch();
  • return 0;
  • }
/********************
 * Switch de string *
 *  par ordiman85   *
 ********************/

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


// char* str est la string à "switcher"
// IMPORTANT !! Mettre 0 comme dernier argument !

#ifdef __cplusplus

// Fonction pour C++
unsigned int s_(char* str, ...)
{
  unsigned int i = 0;
  while (*(++i+&str) != 0)
    if (strcmp(str, (char*)*(&str+i)) == 0)
      return i;
  return 0;
}

#else

// Fonction pour le langage C
unsigned int s_(char* str, char* cmp[])
{
  unsigned int i = 0;
  while (cmp[i] != 0) {
    if (strcmp(str, cmp[i]) == 0)
      return i+1;
    i++;
  }
  return 0;
}

#endif

// Fonction principale
int main()
{
  printf("Test du switch de strings :\r\n");
  // La string à tester est "switch", sa position est 4
  char* String = "switch";

  // On récupère un entier qui correspond à la position de la string identifiée
  
  // Méthode 1 (C++)
  #ifdef __cplusplus

    unsigned int id = s_(String, "Hello", "world", "!", "switch", "strings", 0);

  #else // Méthode 2 (C)

    char* comp[] = {"Hello", "world", "!", "switch", "strings", 0};
    unsigned int id = s_(String, comp);

  #endif

  // Le switch
  switch (id)
  {
    case 1: // "Hello"
      printf("%d. Hello", id);
      break;
    case 2: // "world"
      printf("%d. world", id);
      break;
    case 3: // "!"
      printf("%d. !", id);
      break;
    case 4: // "switch"
      printf("%d. switch", id);
      break;
    case 5: // "strings"
      printf("%d. strings", id);
      break;
    default: // Pas identifié, id = 0
      printf("Pas dans la liste (%d)", id);
      break;
  }

  // Pause et fin
  getch();
  return 0;
}

 Conclusion

J'ai réussi à adapter la fonction en C mais elle ne supporte pas les arguments illimités (il faut un tableau comme 2ème argument)

IMPORTANT : mettez 0 comme dernier argument !

@+


 Historique

15 août 2006 15:49:29 :
Adaptation pour le langage C et simplification de quelques trucs

 Sources du même auteur

Source avec Zip Source avec une capture COURBES NURBS 3D DANS OPENSCENEGRAPH
Source avec Zip BIBLIOTHEQUE FONCTIONNELLE : OPÉRATIONS, COMPOSITION D'OBJET...
Source avec Zip LIBRAIRIE JSON C++
Source avec Zip Source avec une capture [WIN32] EASY WAVE MIXER
Source avec Zip Source avec une capture [C++] HASH FINDER - CALCULATEUR DE HASH

 Sources de la même categorie

Source avec Zip SCHEDULER RR FIFO par yvesB87
Source avec Zip ALGORITHMES RÉCURSIFS VS ALGORITHMES ITÉRATIFS par yvesB87
Source avec Zip Source avec une capture C++ FORMAT D'IMAGE AVEC QT par pop70
Source avec une capture EXEMPLE DE POINTEURS DE FONCTION par pop70
Source avec Zip Source avec une capture [C++] CLASS REGISTER par Miwik

 Sources en rapport avec celle ci

RETOURNER PLUSIEURS ARGUMENTS AVEC LES TUPLES par Davy974
Source avec Zip MYSTRING, CLASSE TRAITANT DES CHAÎNES DE CARACTÈRES par Noubzor
CORRECTEUR DE PONCTUATION par snpier wolf
Source avec Zip CLAVIER TELEPHONE par bustarhy
ALTERNATIVE À LA FONCTION ITOA par Pamaury

Commentaires et avis

Commentaire de luhtor le 15/08/2006 18:07:09

En C++, on peut faire ca plus proprement (à mon gout). En fait, on créer une classe qui encapsule un type énuméré (du style de ca: http://www.codeguru.com/cpp/cpp/cpp_mfc/article.php/c4001/) mais qui permet au passage la conversion indice<=>string.

Toute facon, en C++, je vois pas pk on irait utiliser des (char*).

Commentaire de NitRic le 24/08/2006 21:30:53

« J'ai réussi à adapter la fonction en C mais elle ne supporte pas les arguments illimités (il faut un tableau comme 2ème argument) »

google.com stdarg.h

faut apprendre le langage avant de l'utiliser ...

Commentaire de verdy_p le 18/02/2007 22:00:44

une autre façon de faire est de convertir les strings non modifiables avec une classe de hachage, qui permet ensuite de les comparer directement par leur seul pointeur ou par un entier numérique associé. Dans Windows, on a une API pour ça: CreateAtom() pour utiliser une table de hachage globale pour le système (ou pour l'aplication, le système prenant en charge les transferts d'atomes d'une table de hachage à l'autre). Voir aussi la fonction qui crée une classe de fenêtre selon le même principe, ou les nombreuses autres tables de hachage du système pour les noms de modules (en retour de la conversion de chaine, on obtient un HANDLE entier.
Evidemment on peut avoir des entrées de hachage créées dynamiquement pour lesquelles on ne sait pas quelle sera la valeur de Handle retournée, mais rien n'interdit de créer une table de hachage dont les premières entrées sont prérenseignées, et dont on connait à l'avance la valeur de handle sous forme d'un entier utilisable dans un switch, et on traite les autres valeurs de hachage dans le switch avec "default:" et en les comparant avec ==

Commentaire de verdy_p le 18/02/2007 22:04:24

Juste en passant, c'est une très mauvaise idée de déclarer une variable avec le nom générique "String" (qui ressemble à un nom de classe si on fait du C++)
les variables locales devraient commencer par une minuscule, mais "string" est aussi un type standard dans les librairies C++.

Bref utilise "chaine" ou "str" ou "s", ou "nomUtilisateur" avec un nom parlant associé à ce que représente la variable si la fonction manipule beaucoup de variables...

Commentaire de schlebe le 13/08/2008 11:14:39

Bonjour.

j'utilise une autre technique qui me semble plus efficace, surtout pour la lisibilité du code basée sur l'utilisation de MACRO (#define)

exemple:

#define EVALUATE(s) \
    {\
    string sEvaluate = s;\
    if (false);

#define WHEN(s) \
    else\
    if (sEvaluate == s)
    
#define WhenOTHER \
    else

#define EndEVALUATE \
    }

EVALUATE(sNom)
WHEN("Bernard") cSexe = "M";
WHEN("Chantal") cSexe = "F";
WHEN("Lucien")  cSexe = "M";
WhenOTHER
    {
    cSexe = "?";
    }
EndEVALUATE

Cette technique rend le code plus lisible que l'imbrication de if.
L'instruction EndEVALUATE est également plus explicite que le caractère }.
Il faut cependant remarquer que les blocs WHEN sont totalement séparés et que l'instruction EVALUATE ne peut pas contenir d'instruction "break".
Le nom de la variable locale créée à l'intérieur du bloc annonyme ne peut pas être passé
comme paramètre au risque de perturber l'ensemble.

J'utilise la même technique pour l'instruction SWITCH afin d'éviter un décalage superflu dans l'intruction "case" liée à l'instruction "switch" standard du C/C++.

#define SWITCH(s) \
    switch (s)\
        {

#define EndSWITCH \
        }

exemple:

            SWITCH(sText[0])
            case ',':
                {
                iCode = OP_COMMA;
                bFirstEqual = true;
                break;
                }
            case '(':
                {
                iCode = OP_PAR_OPEN;
                bInFunction = false;
                break;
                }
            case ';': iCode = OP_POINT_VIRGULE;   break;
            case ':': iCode = OP_DOUBLE_POINT;    break;
            case ')': iCode = OP_PAR_CLOSE;       break;
            case '{': iCode = OP_ACCOLADE_OPEN;   break;
            case '}': iCode = OP_ACCOLADE_CLOSE;  break;
            case '[': iCode = OP_SEGMENT_OPEN;    break;
            case ']': iCode = OP_SEGMENT_CLOSE;   break;
            case '.': iCode = OP_POINT;           break;
            EndSWITCH

J'aime également bien la solution de hachage mais elle requiert une organisation plus complexe.

Commentaire de schlebe le 13/08/2008 11:51:36

voici une autre MACRO qui permet l'instruction BREAK

//******************************************************
//* SELECT
//******************************************************

#define SELECT(s) \
    do {\
    string sEvaluate = s;
    bool bFind = false;\

#define CASE(s) \
    if (bFind = (bFind || (sEvaluate.compare(s) == 0)))\

#define CaseOTHER \

#define EndSELECT \
    } while(false);

string sNom = "Bernard";
char cSexe;

SELECT(sNom)
CASE("Lucien");
CASE("Bernard");
CASE("Marc")
    {
    cSexe = 'M';
    break;
    }
CASE("Chantal");
CASE("Marie");
CASE("Colette")
    {
    cSexe = 'F';
    break;
    }
CaseOTHER
    {
    cSexe = '?';
    }
EndSELECT

Attention, lorsqu'une comparaison est bonne mais que le code est exécuté dans un autre bloc, il faut suffixer l'instruction CASE() du caractère ';'.

Remarque: la méthode "compare" est utilisée pour comparer un objet string et un string literal; ce qui n'était pas le cas dans le message précédent.
La même comparaison avec l'opérateur == en Visual C++ 2008 semble ne pas fonctionner.

A+

Commentaire de verdy_p le 01/10/2008 15:50:14

"J'utilise la même technique pour l'instruction SWITCH afin d'éviter un décalage superflu dans l'intruction "case" liée à l'instruction "switch" standard du C/C++."

Voila le genre de macros complètement inutiles qui ne résolvent rien du tout! Si c'est pour une raison d'indentation des accolades, c'est une mauvaise raison! Change d'éditeur de texte contre un qui accepte tes préférences d'indentation (dans mon cas, les "case" sont indentés au même niveau que le "switch" et l'accolade de fermeture par défaut dans tous mes projets (C, C++, C#, PHP, ou Java) mais je n'utilise pas ce genre de macros qui ont de gros inconvénients:
- ces macros sont encore plus longues à taper que la syntaxe originale
- elles dissimulent la syntaxe et introduit un niveau de complexité supplémentaire au code. Une macro ne doit se justifier que si cela simplifie à la fois la lecture et la compréhension du code, et facilite son écriture en évitant de commettre des erreurs subtiles ou des oublis de cas.
- elles cassent les outils de gestion de code, bloquent les replis de blocs dans les bons éditeurs.
On ne règle pas les questions d'indentation de code, qui sont largement des questions de préférences personnelles, avec des macros qui justement n'interagissent pas bien du tout avec la syntaxe du langage (passez un indenteur automatique sur votre code, il ressortira illisible!)
Certains n'aiment pas les indenteurs automatiques, pourtant c'est un gain de temps précieux pour modifier ou restructurer le code tout en assurant de maintenir sa lisibilité (l'indentation à la main est souvent pleine d'erreurs!) et sa maintenabilité.
Bref, gardez les accolades et point-virgules qui sont essentiels à la structure même du langage, hors des macros. Les macros sont fortement déconseillées dans les langages objets car elles sont totalement stupides en terme de typage, et généricité, et en terme d'espace de nommage (rique de collisions). En C++, ce qui les remplace avantageusement chaque fois que possible sont:
- les déclarateurs "enum", et "static const"
- les méthodes et fonctions inline
- les templates
Les macros cela reste de la vieille artillerie pour vieux code en C difficile à maintenir. Gardez quelques macros uniquement pour la compilation conditionnelle (code de débogage, ou code spécifique pour un système lors du portage et l'intégration, à masquer pour les autres plateformes): ces macros devraient n'être que des constantes. (Pas étonnant qu'en C# ou Java, les macros ont été proscrites: il n'y a plus de portage à faire, la machine étant totalement virtualisée par le langage lui-même et ses librairies standards; le reste de la compilation conditionnelle est pris en charge par le chargeur de code et l'éditeur de lien à l'exécution, ainsi que le compilateur/optimiseur JIT, le code n'a plus à être masqué et peut être vérifié avec un seul modèle pour toutes les plateformes, le code "superflu" n'affectant alors pas les performances puisqu'il est éliminé automatiquement si inutilisé).

Dernier point: "l'imbrication de if" dont tu parles est un faux problème. Si on s'en tient à la syntaxe brute du C ou C++, ces "if" successifs sont en fait articulés par des clauses "else" finales. Les séquences de "else if" sont si fréquentes qu'il suffit de considérer que "else if" forme un seul mot clé qui n'interromp pas l'instruction "if" en cours. J'indente toujours ces séquences ainsi:
if (test1) {
   ...
} else if (test2) {
   ...
} else if (test 3) {
   ...
} else if (test 4) {
   ...
}
Pas besoin de rajouter des indentations à l'intérieur d'une clauses "else" pour indenter tout le "if" qui le suit et ses sous-clauses "else" internes.

Enfin dans ton code ci-dessus, je ne vois pas l'intérêt des accolades que tu ajoutes dans certains "case" (ce n'est utile que si tu veux déclarer des variables locales à chaque case sans qu'elles se télescopent mutuellement en terme de type déclaré, d'instanciation, d'initialisation ou de fermeture, mais en général les "switch" qui incluent de telles déclarations locales dans les case deviennent trop longs et les cases devraient faire plutôt appel à des sous-fonctions dans lesquelles ces variables locales seront déclarées et utilisées)

Commentaire de schlebe le 10/10/2008 23:05:28

Vous avez certainement raison sur certains points.
Pour la macro SWITCH il s'agit bien d'une construction pour empêcher l'indentation.

En ce qui concerne la macro EVALUATE je la préfère à la construction else-if et je regrette que cette Macro ne soit pas implémentée en standard dans le langage C++.

Je pense qu'il est plus facile d'écrire:

EVALUATE(sNom)
WHEN("Bernard") cSexe = "M";
WHEN("Chantal") cSexe = "F";
WHEN("Lucien")  cSexe = "M";
WhenOTHER
    {
    cSexe = "?";
    }
EndEVALUATE

que

if (sNom == "Bernard") cSexe = "M";
else if (sNom == "Chantal") cSexe = "F";
else if (sNom == "Lucien")  cSexe = "M";
else
    {
    cSexe = "?";
    }

Pour ma part je dois encore ajouter que la macro EVALUATE simplifie le code en évitant au programmeur de commettre une faute dans les égalités et tout en lui évitant d'écrire les égalités autant de fois qu'il n'y a de IF.

D'expérience je sais qu'il est extrêment facile de commettres des erreurs comme ci-dessous.

if (sNom == "Bernard") cSexe = "M";
else if (sNon = "Chantal") cSexe = "F";
else if (sNom = "Lucien")  cSexe = "M";
else
    {
    cSexe = "?";
    }

L'utilisation de la macro EVALUATE évite ce genre de problème.

Je vais même plus loin dans l'utilisation de la macro WHEN.
Je défini une Macro WHENx pour comparer selon un algorithme particulier.

Voici un exemple et son interprétation avec des ELSE-IF

    EVALUATE(this->GetParamString("INFO"))
    WHEN ("*STD")            iInfo = MODIFY_DATE;
    WHEN ("*ALL")            iInfo = ALL;
    WHENx("N[AME]")          iInfo = NAME;
    WHENx("S[IZE]")          iInfo = SIZE;
    WHENx("NUM[BER]")        iInfo = NUMBER;
    WHENx("C[REATE]-D[ATE]") iInfo = CREATE_DATE;
    WHENx("M[ODIFY]-D[ATE]") iInfo = MODIFY_DATE;
    WHENx("A[CCESS]-D[ATE]") iInfo = ACCESS_DATE;
    EndSWITCH

ou avec IF-ELSE

    string s = this->GetParamString("INFO");

    if (s == "*STD") { iInfo = MODIFY_DATE;
    } else if (s == "*ALL") { iInfo = ALL;
    } else if (Comparex(s,"N[AME]")) iInfo = NAME;
    } else if (Comparex(s,"S[IZE]")) iInfo = SIZE;
    } else if (Comparex(s,"NUM[BER]") iInfo = NUMBER;
    } else if (Comparex(s,"C[REATE]-D[ATE]") iInfo = CREATE_DATE;
    } else if (Comparex(s,"M[ODIFY]-D[ATE]") iInfo = MODIFY_DATE;
    } else if (Comparex(s,"A[CCESS]-D[ATE]") iInfo = ACCESS_DATE;
    }

Il s'agit de code pour interpréter une valeur de paramètre dans une commande en mode ligne sur une machine BS2000 (Mainframe Fujitsu-Siemens) mais qui fonctionne également sous Windows. La fonction Comparex compare le premier paramètre avec le second, les caractères entre [ ] indiquent que ces caractères ne sont pas obligatoires.
Dans la commande l'utilisateur peut écrire INFO=ACC-DATE ou A-D mais pas ACC.

Petite information pour le lecteur. Je programme en C depuis 1986 et en C++ depuis 1990.
Au début j'ai utilisé le if-else, puis j'en ai eu marre de cette technique alors que les autres langages que je pratique couramment tel le COBOL, Java et VisualBasic 6.0 et .Net avait tous des fonctions de SWITCH sur les String.

En fait EVALUATE est l'instruction d'évaluation en COBOL !

Je peux également ajouter que j'aime également beaucoup le code aéré dont la structure et les finesses sautent tout de suite aux yeux de tous les programmeurs.

Essayer cette technique, c'est l'adopter !


Commentaire de verdy_p le 13/10/2008 03:36:31

évidemment, pour ceux qui préfèrent indenter les accolades au même niveau, il vaut mieux les indenter avec leur contenu, cela donne:
if (test1)
   {
   ...
   }
else if (test2)
   {
   ...
   }
else if (test 3)
   instruction;
else if (test 4)
   {
   instruction1;
   instruction2;
   }
else
   {
   ...
   }
Dans tous les cas, je laisse "else if" groupé sur la même ligne, et je n'indente jamais le if après le else, surtout quand les conditions sont mutuellement exclusives comme ici (leur ordre d'évaluation est indifférent, une seule branche est prise, ce qui est justement le sujet ici avec un "switch" de chaines différentes) !

Les indenteurs automatiques de nombre d'ateliers de développement ou d'éditeurs de texte pour programmeurs reconnaissent tous la séquence "else if" (et certains langages en font un seul mot-clé "elseif" ou "elsif" ou "elif", y compris le préprocesseur C/C++ avec "#elif")

Commentaire de verdy_p le 13/10/2008 03:55:13

Comment veux-tu que "EVALUATE" fonctionne en C++? Il faudrait définir ce qui définit une égalité entre deux types ou objets en C++. Hors les chaines ne sont pas des objets, juste des pointeurs vers peut-être un seul caractère, et pas forcément une chaine.
Au mieux, cet EVALUATE ne pourra que comparer les pointeurs, et il n'y a aucune chance que ça marche puisque ce que tu veux implicitement c'est comparer non pas les pointeurs (qui sont différents) ni le caractère qu'ils pointent chacun, mais la suite de caractères terminée par des NULs, ce que le type "char *" (ou "const char *" pour les constantes chaines) n'indique pas du tout.
Il faudrait donc d'abord transtyper le paramètre de EVALUATE() pour le passer d'un type "char*" en un type objet "string", lequel dispose de la surcharge de l'opérateur == qui accepte un paramètre "char*". Si on est en C (et pas en C++) c'est impossible.
L'essayer chez moi, c'est tout SAUF l'adaopter.
De toute façon ta "technique" ne marche pas avec les indenteurs automatiques car cela ne respecte pas la syntaxe de base des instructions.
Ton code:
    EVALUATE(this->GetParamString("INFO"))
    WHEN ("*STD")            iInfo = MODIFY_DATE;
    WHEN ("*ALL")            iInfo = ALL;
    WHENx("N[AME]")          iInfo = NAME;
    WHENx("S[IZE]")          iInfo = SIZE;
    WHENx("NUM[BER]")        iInfo = NUMBER;
    WHENx("C[REATE]-D[ATE]") iInfo = CREATE_DATE;
    WHENx("M[ODIFY]-D[ATE]") iInfo = MODIFY_DATE;
    WHENx("A[CCESS]-D[ATE]") iInfo = ACCESS_DATE;
    EndSWITCH
    suite du code;
    suite du code;
s'indentera alors:
    EVALUATE(this->GetParamString("INFO")) WHEN ("*STD") iInfo = MODIFY_DATE;
    WHEN ("*ALL") iInfo = ALL;
    WHENx("N[AME]") iInfo = NAME;
    WHENx("S[IZE]") iInfo = SIZE;
    WHENx("NUM[BER]") iInfo = NUMBER;
    WHENx("C[REATE]-D[ATE]") iInfo = CREATE_DATE;
    WHENx("M[ODIFY]-D[ATE]") iInfo = MODIFY_DATE;
    WHENx("A[CCESS]-D[ATE]") iInfo = ACCESS_DATE;
    EndSWITCH suite du code;
    suite du code;
(la première et la dernière ligne sont mal indentées et fusionnées en une seule ligne, l'indenteur croyant y voir une seule instruction). Si l'indenteur veut faire des renvois à la ligne on obtient:
    EVALUATE(this->GetParamString("INFO"))
        WHEN ("*STD") iInfo = MODIFY_DATE;
    WHEN ("*ALL") iInfo = ALL;
    WHENx("N[AME]") iInfo = NAME;
    WHENx("S[IZE]") iInfo = SIZE;
    WHENx("NUM[BER]") iInfo = NUMBER;
    WHENx("C[REATE]-D[ATE]") iInfo = CREATE_DATE;
    WHENx("M[ODIFY]-D[ATE]") iInfo = MODIFY_DATE;
    WHENx("A[CCESS]-D[ATE]") iInfo = ACCESS_DATE;
    EndSWITCH
       suite du code;
    suite du code;
Ce qui est totalement illogique (comment veux-tu que l'indenteur y reconnaisse quelquechose à tes macros ? D'autant que les macros sont connues pour leurs effets de bord désastreux. Ici il y a bien un effet de bord, puisque tu y introduit un bloc contenant deux variables locales: "sEvaluate" et "bFind", qui entreront tôt ou tard en conflit avec le code que tu voulais mettre  après chaque WHENx(...), puisque tu casses la portée de variables homonymes déclarées avant le bloc EVALUATE.
Tu n'as même pas pris la peine de nommer ces variables déclarées par une macro avec un double-underscore en préfixe, pour éviter les collisions avec les variables du reste du code.

Autre danger: WHENx() ou CASE  suppose qu'il est suivi d'une seule instruction (sinon le "if" qu'il contient ne rendra conditionnelle que la première instruction. Il serait plus logique alors d'écrire non pas:
    CASE("Marc")
        {
        cSexe = 'M';
        break;
        }
Mais simplement:
    CASE("Marc")
        cSexe = 'M';
        break;
Hors si on l'écrit comme ça, cela ne marche pas puisque le" break;" n'est plus conditonnel, et le reste des CASE ne sera jamais évalué. Voilà comment on peut se perdre avec des macros dangereuses.

Commentaire de verdy_p le 13/10/2008 04:31:45

Autre problème cette fois, montrant combien tu t'es perdu dans l'exemple tu donnes:
    EVALUATE(sNom)
    CASE("Bernard")
    CASE("Lucien")
    masculin:
        {
        cSexe = 'F';
        break;
        }
    CASE("Chantal");
    CASE("Marie");
    CASE("Colette")
        {
        cSexe = 'F';
        break;
        }
    WhenOTHER
        {
        cSexe = "?";
        }
    EndEVALUATE
et tu supposes que les trois prénoms féminins provoqueront l'évaluation de "csexe = 'F'". C'est entièrement faux ici: les deux premiers CASE génèrent chacun un if dans le contenu est vide (ces deux tests sont réalisés pour rien on passe à la suite le troisième CASE avec Colette sera alors faux pour Chantal et Marie, donc ne fera rien du tout non  (non! cSexe ne sera pas modifié!!)

Pour que ça marche il faudrait écrire ça:
    EVALUATE(sNom)
    CASE("Bernard") goto _cas1;
    CASE("Lucien")  goto _cas1;
    CASE("Chantal") goto _cas2;
    CASE("Marie")   goto _cas2;
    CASE("Colette") goto _cas2;
    WhenOTHER       goto _cas0;
    _cas1:
        {
        cSexe = 'F';
        break;
        }
    _cas2:
        {
        cSexe = 'F';
        break;
        }
    _cas0:
        {
        cSexe = "?";
        }
    EndEVALUATE
Ce qui n'est pas très propre il faut l'avouer, et encore moins clair! (note que pour que des cases successifs conduisent à la même branche de code, il faut simuler un "ou", ce qui se fait par des goto vers une même étiquette. On est obligé aussi de déplacer le code des branches après TOUS les CASE, c'est à dire après tous les "goto" conditionnés par un "if". Note que sous cette forme on peut tout à fait se passer des accolades autour des branches Ceci marche aussi:
    EVALUATE(sNom)
    CASE("Bernard") goto _cas1;
    CASE("Lucien")  goto _cas1;
    CASE("Chantal") goto _cas2;
    CASE("Marie")   goto _cas2;
    CASE("Colette") goto _cas2;
    WhenOTHER       goto _cas0;
    _cas1:
        cSexe = 'F';
        break;
    _cas2:
        cSexe = 'F';
        break;
    _cas0:
        cSexe = "?";
    EndEVALUATE
(l'instruction break; marche de même que la continuation, comme dans un switch C/C++ normal car le bloc "EVALUATE...EndEVALUATE" est une boucle "do{...}while(0);"). En effet l'expansion des macros devient (j'ai simplifié ici les parenthèses que tu as mis dans tes "if"):
    do{ string sEvaluate = sNom; bool bFind=false;
    if ((bFind = bFind || sEvaluate.compare("Bernard") == 0) goto _cas1;
    if ((bFind = bFind || sEvaluate.compare("Lucien") == 0)  goto _cas1;
    if ((bFind = bFind || sEvaluate.compare("Chantal") == 0) goto _cas2;
    if ((bFind = bFind || sEvaluate.compare("Marie") == 0)   goto _cas2;
    if ((bFind = bFind || sEvaluate.compare("Colette") == 0) goto _cas2;
    /*other*/ goto _cas0;
    _cas1:
        cSexe = 'F';
        break;
    _cas2:
        cSexe = 'F';
        break;
    _cas0:
        cSexe = "?";
    } while (0);
Sous cette forme, il parait évident qu'on peut se passer totalement de la variable temporaire bFind et écrire simplement (et plus efficacement aussi à l'exécution, avec même la même efficacité que si on avait utilisé des ou "||" dans un if):
    do{ string sEvaluate = sNom;
    if (sEvaluate.compare("Bernard") == 0) goto _cas1;
    if (sEvaluate.compare("Lucien") == 0)  goto _cas1;
    if (sEvaluate.compare("Chantal") == 0) goto _cas2;
    if (sEvaluate.compare("Marie") == 0)   goto _cas2;
    if (sEvaluate.compare("Colette") == 0) goto _cas2;
    /*other*/ goto _cas0;
    _cas1:
        cSexe = 'M';
        break;
    _cas2:
        cSexe = 'F';
        break;
    _cas0:
        cSexe = "?";
    } while (0);
Personnellement j'en reste à la solution simple, sans macros:
    do{
        string sEvaluate = sNom;
        if (sEvaluate.compare("Bernard") == 0 ||
            sEvaluate.compare("Lucien" ) == 0) goto _cas1;
        if (sEvaluate.compare("Chantal") == 0 ||
            sEvaluate.compare("Marie"  ) == 0 ||
            sEvaluate.compare("Colette") == 0) goto _cas2;
        goto _cas0;
    _cas1:
        cSexe = 'M';
        break;
    _cas2:
        cSexe = 'F';
        break;
    _cas0:
        cSexe = "?";
    } while (0);
Mais ces goto ici, quel gachis, quand les clauses sont mutuellement exclusives et toutes terminées par un break; autant écrire directement:
    {
    string sEvaluate = sNom;
    if (sEvaluate.compare("Bernard") == 0 ||
        sEvaluate.compare("Lucien" ) == 0)
        cSexe = 'M';
    else
    if (sEvaluate.compare("Chantal") == 0 ||
        sEvaluate.compare("Marie"  ) == 0 ||
        sEvaluate.compare("Colette") == 0)
        cSexe = 'F';
    else
        cSexe = "?";
    }
Ici le else joue le rôle des "break" dans le switch. Pas besoin d'être sorcier et savoir comment sont faites les macros externes pour deviner ce que fait ce code.

Commentaire de verdy_p le 13/10/2008 04:46:10

évidemment, pour ceux qui préfèrent indenter les accolades au même niveau, il vaut mieux les indenter avec leur contenu, cela donne:
if (test1)
   {
   ...
   }
else if (test2)
   {
   ...
   }
else if (test 3)
   instruction;
else if (test 4)
   {
   instruction1;
   instruction2;
   }
else
   {
   ...
   }
Dans tous les cas, je laisse "else if" groupé sur la même ligne, et je n'indente jamais le if après le else, surtout quand les conditions sont mutuellement exclusives comme ici (leur ordre d'évaluation est indifférent, une seule branche est prise, ce qui est justement le sujet ici avec un "switch" de chaines différentes) !

Les indenteurs automatiques de nombre d'ateliers de développement ou d'éditeurs de texte pour programmeurs reconnaissent tous la séquence "else if" (et certains langages en font un seul mot-clé "elseif" ou "elsif" ou "elif", y compris le préprocesseur C/C++ avec "#elif")

Commentaire de verdy_p le 13/10/2008 05:07:01

Note encore: le premier code donné soit-disant pour C++ est bogué! Je cite:

// Fonction pour C++
unsigned int s_(char* str, ...)
{
  unsigned int i = 0;
  while (*(++i+&str) != 0)
    if (strcmp(str, (char*)*(&str+i)) == 0)
      return i;
  return 0;
}

En fait ce n'est pas spécifique à C++ (car les varargs existent aussi en C) mais il y a un sérieux problème de compatibilité. En effet rien ne dit que les paramètres passés en varargs seront rangés en mémoire dans l'ordre croissant et de façon contigue. Si vous portez ça sur un processeur 64 bits vous aurez des surprises car justement c'est faux :
* Les premiers paramètres sont passés via des registres,
* Les autres paramètres sont empilés (mais ni le C ni le C++ n'indique dans quel ordre (de droite à gauche ou de gauche à droite: cela dépend des conventions d'appel, la convention cdecl empile de gauche à droite les paramètres déclarés, mais il y a d'autres conventions comme pascal, fastcall, stdcall...), ni non plus l'orientation de la pile (qui est toutefois descendante sur les architectures Intel x86 ou x64 ou AMD64, et PowerPC sur Mac, mais cela dépend des systèmes d'exploitation: c'est vrai pour DOS, Windows, MacOS, OSX, Linux, mais pas partout)
* A l'entrée dans la fonction, les paramètres passés dans des registres seront éventuellement copiés dans un bloc au sommet de la pile, mais après les autres paramètres, les pointeurs de framing et de retour. Il y aura donc un décalage entre les premiers paramètres (copiés des registres vers le bloc DANS la fonction elle-même, ce qui n'est sur car la fonction compilée peut se passer de cette sauvegarde dans certaines cnoditions, et les paramètres suivants)

Pour que ca marche et que ce soit portable il faut inclure <stdarg.h> et utiliser les macros de varargs documentés (déclarer un pointeur "p" de type "va_list", l'initialiser avec "va_start(p)", lire les paramètres avec "va_next(p, type)" et à la fin utiliser "va_end(p)" pour libérer certaines ressources éventuellement allouées par "va_start(p)" pour créer un bloc descripteur linéaire et ordonné, compatible avec une lecture séquentielle par "va_next(p, type)";

Ne croyez pas que "va_next()" est très simple: si vous portez pour la plateforme .Net par exemple, (où le code C/C++ est compilé d'abord en language MSIL, qui sera compilé en code natif sur la machine cible lors de l'installation du programme ou de sa première exécution; pour assurer l'isolation stricte, .Net imposera une vérification des paramètres, et les variables empilées sont décrites en fait à l'aide d'un bloc descripteur généré lors de la compilation, les pramètres ne pouvant pas s'analyser sans ce descripteur de sécurité qui indique quels traitement sont autorisés dessus, et empêchera donc de lire les paramètres au delà des limites des véritables arguments passés à la fonction).

Il ne faut pas essayer de lire l'adresse d'un paramètre soi-même pour en déduire la position d'un autre paramètre dans la pile. Et c'est valable aussi bien en C qu'en C++ (en C++ la déclaration de fonction DOIT utiliser "...", alors qu'en C ce n'est pas obligatoire, mais c'est possible aussi en C ANSI; en C de type K&R, on peut aussi uiliser les varargs en incluant <vararg.h> mais la syntaxe est légèrement différente).

Commentaire de schlebe le 13/10/2008 21:39:52

A force de vouloir raison vous en perdez la raison !

Petites explications pour les lecteurs qui viendraient à tomber sur cet amassis de monologue sans possiblité d'intervenir et de répondre point pas point.

<b>Indentation du premier if</b>

Il est évident que j'aurais pû écrire.
     if (s == "Bernard")
else if (s == "Chantal")
etc ..

Mais comme dans votre remarque vous preniez comme argument que vous utilisez un indentateur automatique, j'ai fait comme font tous les indentateurs automatiques et j'ai placé le premier if sur la première colonne.
Si vous argumentez en utilisant l'indentation ayez au moins la courtoisie de respectez votre choix et de ne pas donner un exemple contraire quelques lignes plus bas.

<b>fonction de comparaison sur chaines de caractères</b>

Vous écrivez qu'il faut d'abort transtyper la chaîne de caractères en un type string car la chaîne de caractères n'a pas d'opérateur de comparaison.
C'est vrai, mais c'est ce que j'ai fait, pour info, voici la macro EVALUATE

#define EVALUATE(s) \
    {\
    string sEvaluate = s;\
    if (false);

Vous indiquez que c'est impossible en C.
C'est vrai.

<b>Introduction de GOTO</b>

La solution avec des gotos est totalement burlesque. Je ne vois pas pourquoi vous faites des exemples compliqués. Serait-il possible de garder les pieds sur terre et de traiter calmement du problème.

<b>Nom des variables simplistes</b>

Je suis totalement d'accord avec vous, les variables locales (à l'intérieur de la macro EVALUATE aurait pû être mieux choisie.
Mea culpa.

<b>Le code de la macro SELECT ne fonctionne pas</b>

L'erreur étant humaine, j'ai copié mon code sous Visual C++ .Net 2007 et il a fonctionné correctement.
J'ai porté mon code sous C++ 3.1B sous BS2000, il a également fonctionné correctement.

Pourriez-vous être plus correct et ne pas déclarer que mes affirmations sont erronées sans avoir pris vous même le temps de les tester ?

Le code C++ sous Visual C++ est le suivant :

// TestMacro.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <string>

using namespace std;

#define SELECT(s) \
    do {\
    string sEvaluate = s;\
    bool bFind = false;\

#define CASE(s) \
    if (bFind = (bFind || (sEvaluate == s)))\

#define CaseOTHER \

#define EndSELECT \
    } while(false);

static void DisplaySexe(string sNom)
    {
    char cSexe;

    SELECT(sNom)
    CASE("Lucien");
    CASE("Bernard");
    CASE("Marc")
        {
        cSexe = 'M';
        break;
        }
    CASE("Chantal");
    CASE("Marie");
    CASE("Colette")
        {
        cSexe = 'F';
        break;
        }
    CaseOTHER
        {
        cSexe = '?';
        }
    EndSELECT
    cout << ">> Sexe [" << sNom << "] = " << cSexe << endl;
    }

int _tmain(int argc, _TCHAR* argv[])
{
    DisplaySexe("Lucien");
    DisplaySexe("Marc");
    DisplaySexe("Bernard");
    DisplaySexe("Chantal");
    DisplaySexe("Marie");
    DisplaySexe("Colette");
    DisplaySexe("Philippe");

    return 0;
}

C.Q.F.D.

Commentaire de verdy_p le 14/10/2008 12:43:17

L'introduction des goto est ici nécessaire pour que les instruction des branches du swith se fase comme prévu.

Ce n'est pas plus idiot que ce que fait REELLEMENT un switch (qui est effectivement une forme compliquée de "goto" multiples à l'intérieur d'un bloc, où chaque "case...:" est effectivement un label). (si tu n'en es pas convaincu compile un switch en source assembleur; la seule différence est qu'un switch peut aussi éventuellement se compiler en un goto indexé (en utilisant une table d'addresses) si les valeurs des cases sans le switch entier sont un peu nombreuses, mais à peu près groupées dans un intervalle petit (mais même dans ce cas la compilation doit tester les bornes avant de faire une indirection).

Ce que je voulais montrer c'est que tes macros restent toujours aussi dangereuses: tu les utilises pour mettre 1 seule instruction apès chaque CASE, sinon il te faut mettre des accolades pour former un bloc. Oublie une accolade, ou le fait que d'autres instructions sont générées (de façon masquée par des macros comme ici) en plusieurs, et tu te retrouves avec un bogue inattendu car seule la première instruction du bloc sera condionnelle, les suivante seront exécutées de façon inconditionnelle alors que le cas d'égalité du switch n'a pas encore été atteint et vérifié.

Des gotos n'ont rien de mauvais en soi, même si c'est vrai que c'est moins lisible que les structures de contrôle usuelles qui devraient être utilisées (if...else, while..., do...while, for..., switch...) chaque fois que possible. On peut faire du code incompréhensible, c'est vrai avec des gotos, mais on peut faire encore pire avec des macros aux effets de bords inattendus. Le bon usage reste encore de ne pas en abuser pour aller dans tous les sens dans un bloc, et de limiter leur portée à un seul bloc. L'usage des goto en aval uniquement respecte cette contrainte de lisibilité (pour les sauts en amont, il y a normalement unboucle qui devait être explicite avec do..while, while.. ou for.., et les sauts amonts doivent revenir à un seul point et non plusieurs.

Les goto sont principalement utilisés en C/C++ pour justement faire des automates d'état finis pour lesquels l'état suivant de chaque étape est déterminé par l'évaluation de toute une série de conditions (en principe exclusives, comme dans un switch C/C++, mais ce n'est pas toujours le cas quand les conditions testent d'abord des exceptions puis traitent différement des cas généraux). Le switch du C/C++ est très pauvre non pas par le fait fait qu'il effectue bien des gotos, mais par le fait que les conditions qu'il sait évaluer sont trop limitées à la seul égalité binaire stricte (il lui manque les conditions d'intervalles, les listes de priorité, la comparaison des objets ne serait-ce que pour leur égalité relative. c'est là justement que la combinaison "if() goto" prend son sens (à condition effectivement de limiter le sens et la portée des gotos). dernier point: les gotos sont très efficaces à l'exécution; La source d'inefficacité ce n'est pas les branchements inconditionnels mais bien les branchements conditionnels (c'est-à-dire if, for, while...), mais encore pire, l'utilisation de tests basés sur les valeurs de variables temporaires (comme ici: l'affectation et le test de la variable génère des temps d'attente, et monopolise des registres et réduit l'eficacité du cache, à moins que le compilateur soit très bon et détermine le cycle de vie de ces varaibles et décide de les éliminer totalement de façon prédictive)

Là on discute justement d'un cas où le switch est insuffisant. Et je ne vois pas du coup quel risque il y a à utiliser un "if...else if...else if..." directement sans utiliser de macros, ni de variables bouléennes supplémentaires juste pour tester si un des cas a déjà été traité.

Et je reste sérieux, sans offenser qui que ce soit personnellement.

C.Q.F.N.D.

Commentaire de geek1983 le 11/09/2009 20:01:59

Eh... Pardon, je ne sais pas en C++ mais en C# c'est possible de faire un switch sur des char en utilisant des single quote:

    char option = 'abc';

    switch (option)
    {
        case 'abc':
            printf("abc");
            break;
        case 'def':
            printf("def");
            break;
        default:
            printf("Error");
            break;
    }

Commentaire de verdy_p le 12/09/2009 01:32:14

Parler de C# ici est impropre. On est justement dans le site/forum pour le C++. Le C-sharap est un autre langage, très différent dans sa structure comme son fonctionnement et ses principes (il l'est tout autant éloigné de C++ que Java). Ce que voulait l'auteur c'est "alléger" l'écriture de switches sur des valeurs de chaines, une chose quene prend pas en charge nativement le C++ (même en utilisant des classes, car le switch du C++ n'est pas utilisable pour les classes, car il ne permet pas la surcharge de son opérateur d'égalité, et se contente de comparer les pointeurs d'instances, à condition de les promouvoir en entiers et ce qui n'est pas portable, et n'autorise pas le switch sur les références non plus).
Personnellement je n'utilise jamais ce genre de code proposé, mais j'utilise des fonctions de hachage (qui donne un switch bien plus efficace): c'est d'ailleurs cette méthode qu'utilise aussi Java qui permet de convertir les Strings, immuables, en atomes uniques, et le fait automatiquement pour toutes les chaines constantes présentes dans le source des classes : dans ce cas l'égalité stricte des références seulement devient possible.

Le défaut cependant des atomes (soluble) est la capacité de son dictionnaire de stockage, cette méthode de conversion en atomes pouvant être couteuse en mémoire si elles y restent ; mais Java, comme aussi C#, résoud ce problème en utilisant un marquage des références d'instances, et son rammsse-miettes automatique quand l'instance unique n'est plus utilisée ni dans les sources d'une classe active, ni dans les objets qui l'ont référencée ou créée temporairement (par exemple si les chaines viennent d'une entrée-sortie temporaire pendant un traitement de données massives et ne correspondent à aucune des chaines constantes présentes dans les sources de la classe de traitement).

Dans ce cas, le hachage des chaines et leur recherche dans un dictionnaire est une méthode très efficace et permet des traitements très rapides et efficaces, plus rapides même que ce que ferait un switch effectuant des tas de comparaisons de chaines. Dans certains cas, la méthode de hachage utilisée permet d'obtenir aussi un entier représentant exactement toute la valeur de la chaine parmi les valeurs constantes attendues (possible si les valeurs possibles ont une syntaxe restreinte avec peu de variantes, de sorte que toute l'information peut tenir dans un même entier): il n'est alors pas nécessaire d'utiliser un dictionnaire, et on peut se contenter de faire un switch directement sur la valeur entière de hachage.

Si les valeurs de hachage attendues sont contenues dans un intervalle petit, on peut aussi faire une simple indirection via un tableau, mais le switch du C++ choisit la bonne méthode en fonction de la taille du tableau: s'il y a peu de valeurs, il ne stocke aucun tableau et génère une suite de if/else imbriqués de façon dichotomiques, sinon il utilise stocke un tableau de valeurs et une table d'indirection associée, et utilise une fonttion de recherche dichotomique dans le tableau de valeur pour minimiser le nombre de if/else imbriqués et réduire la taille du code généré (une recherche dichomomique dans une boucle très petite est plus efficace en terme de cache/mémoire qu'une trop longue suite de if/else, car la boucle utilise la localité).

Si le nombre d'éléments dans le tableau est vraiment très faible (3 ou moins), il se contente de comparer les éléments un par un (pour minimiser le nombre de branchements conditionnels, et me^me le nombre de branchements inconditionnels).

Divers paramètres de performance permettent d'indiquer au compilateur C++ quelle méthode utiliser pour générer des switches efficaces, mais si on n'utilise pas le switch du C/C++, c'est à nous de faire le code simulant le même effet. Ils varients selon les compialteurs, mais presque tous aujourd'hui ont de telles options.

Mais le but du script donné plus haut n'est pas là: il ne s'agit pas de performance mais uniquement de lisibilité du code ou de facilité d'écriture (ce dont je ne suis pas du tout convaincu car le code est encore trop verbeux et pas pratique à taper, ni stable au plan du typage, un défaut des macros, ni forcément plus lisible que des ifs correctement indentés, et je ne voit pas l'intérêt de mettre les accolades dans les macros (puisque cela casse les outils d'indentation automatique des éditeurs de code, très pratiques et très rapides dès qu'on touche au code pour le restructurer, ou encore quand on utilise des éditeurs effectuant de la génération de code automatique, par exemple sous Eclipse avec les fonctions dites de "refactoring").

Les accolades étant reconnues automatiquement et faisant déjà l'essentiel de la structure du code, je ne vois pas ce qu'on gagne à les cacher (sauf si elles sont totalement ouvertes et refermées dans la MÊME macro, ce qui n'est pas le cas ici).

 Ajouter un commentaire


Discussions en rapport avec ce code source dans le forum

Problème sur un strcmp... [ par Clonk ] Bonjour,voilà, je dois rechercher dans un fichier si chaque ligne correspond à un masque donné (chaque masque est stocké dans une classe). Voilà comme Switch et char [ par Stoomm ] Bonjour,Si j'ai :char test[10];strcpy (test, "monchar ";Si je souhaite faire un switch : Je fais comment ???switch (test){...}Il aime pas ! Quelqu'un exécuter java avec prog en c [ par Bashi ] Bonjour, j'ai essayé d'utiliser un code c pour exécuter du java sous windows, je le compile avec Digital Mars. Mon fichier java est GPS.java et j'ai u pb pour l'affichage d'un tableau [ par blinix123 ] #include &lt;stdlib.h&gt;#include &lt;iostream.h&gt;#include &lt;stdio.h&gt;#include &lt;string.h&gt; &nbsp; &nbsp; struct cd{&nbsp;char artiste [64]; Utilisation des arguments int argc et char *argv[] [ par christophedlr ] Bonjour à tous,Je voudrais savoir comment faire pour tester si un argument de la ligne de commande est par exemple --help pour afficher l'aide par exe Switch texte [ par lastpixl ] Est-il possible de faire un switch sur du texte ? Mon compilateur me fait une erreur à chaque fois que j'essaie avec une chaine.ca marche avec un char char**, pointeur et fonction [ par psykocrash ] Salut,Je bosse sur un petit programme et je butte sur un problème de pointeurs. Voici le code source qui pose problème :--------------------#include & Erreur de segmentation : à cause d'un strcmp() [ par tibs624 ] Tout est dit dans le titre à la compilation aucun problème mais lors de l'exécution de mon programme. Je vous met le code et les explications. Ce code Petit problem avec switch [ par Darkneon ] Salut, Mon but est de faire bouger le curseur a l'ecran avec les fleches et d'afficher une lettre a cette position.J'ai le codde suivant.#include &l Comment convertir LPCSTR >> CHAR ou autre... [ par Tyrael369 ] Salut,je voulais savoir comment convertir un LPCSTR afin de le mettre dans un fichier...++Tyrael


Nos sponsors


Sondage...

Comparez les prix

CalendriCode

Février 2012
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
272829    

Consulter la suite du CalendriCode

Photothèque

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 1,732 sec (4)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales