Partage
  • Partager sur Facebook
  • Partager sur Twitter

Lire dans un fichier

De C à C++

    3 août 2007 à 23:35:29

    Bonjour à tous, j'ai quelques questions à vous poser :)

    1°) Les fonctions qui permettaient de lire dans un fichier en C me paraissaient satisfaisantes, en dehors du fait de respecter la POO en C++, quel est l'intêret de changer tout ça ? Il y a un gain de temps, de mémoire ?

    2°) J'ai codé la première partie d'un jeu vidéo avec l'aide de SDL et FMOD. Comme j'ai suivi les cours du SdZ, mes lectures/écritures dans les fichiers se faisaient en C avec les pointeurs FILE* etc.. J'ai décidé, afin de m'améliorer en C++, de réécrire dans ce même langage tout ce que j'avais auparavant écrit en C, et j'ai commencé par les lectures/écritures dans les fichiers.
    Néanmoins, en envoyant le .rar contenant l'exécutable et tout le reste à un ami, celui-ci m'a dit qu'une fonction que j'avais implémentée dans le jeu ne fonctionnait pas, alors que cette même fonction s'exécute correctement chez toutes les autres personnes à qui j'ai envoyé le "jeu".
    Le problème, c'est que cette fonction (qui se sert des lectures/écritures dans un fichier) est codée en C o_O (je n'ai pas fini tous les changements). Je n'ai donc effectué aucune modification sur cette partie du code ! Ma question est donc la suivante : peut-il y avoir des problèmes de compatibilité au sein du programme si à certains endroits j'utilise du C et à d'autres du C++ ? (à priori je ne vois pas pourquoi mais bon...)

    Voici la fonction en question, elle teste si l'on a cliqué sur des boutons "Suivant" ou "Précédent" afin de charger en mémoire et de lire une nouvelle musique de fond :

    SDL_Surface* changerMusique(Uint16 x, Uint16 y, FMUSIC_MODULE* musiqueEnCours, SDL_Surface* nomMusique)
    {     
         if(((x >= 376 && x <= 398) && (y >= 189 && y <= 218)) || ((x >= 593 && x <= 615) && (y >= 189 && y <= 218))) // Si on a cliqué sur "Suivant" ou "Précédent"
         {
          TTF_Font *incised_black = TTF_OpenFont("polices\\Incised_Black.ttf", 25);
         
          SDL_Color couleur = {0, 0, 255};
         
          int numeroPiste = 0;
         
          string Musique[8]
          string musiqueDeFond;
           
          char nom1[MAX_CONFIG];
          char nom2[MAX_CONFIG];
          char musiqueDansConfig[MAX_CONFIG];
         
         
          FILE *config = fopen("config.txt", "r");
         
         
          if(config == NULL)
          {
           fprintf(stderr, "Erreur d'ouverture du fichier config.txt lors du changement de musique.");
          }
          else
          {
           fscanf(config, "NOM1: %s\nNOM2: %s\nMUSIQUEFONDMENU: %s\nNUMEROPISTE: %d", &nom1, &nom2, &musiqueDansConfig, &numeroPiste);
           fclose(config);
          }
         
         
          static int numMusique = numeroPiste;
         
         
          FILE *configModifie = fopen("config.txt", "w+");
         
         
          Musique[0] = "Sons\\ymca.mid";
          Musique[1] = "Sons\\sex_machine.mid";
          Musique[2] = "Sons\\black_or_white.mid";
          Musique[3] = "Sons\\enjoy_the_silence.mid";
          Musique[4] = "Sons\\sunday_bloody_sunday.mid";
          Musique[5] = "Sons\\cannabis.mid";
          Musique[6] = "Sons\\sexo_y_religion.mid";
          Musique[7] = "Sons\\como_me_pongo.mid";
         
         
          // Si l'on clique sur la flèche "Musique précédente"
         
          if( ( (x >= 376 && x <= 398) && (y >= 189 && y <= 218) ) && numMusique > 0)
           numMusique--;

         
          // Si l'on clique sur la lfèche "Musique suivante"
         
          if( ( (x >= 593 && x <= 615) && (y >= 189 && y <= 218) )  && numMusique < 7)
           numMusique++;
         
         
           musiqueEnCours = FMUSIC_LoadSong(Musique[numMusique].c_str());
           FMUSIC_PlaySong(musiqueEnCours);
         
         
         
          switch(numMusique)
          {
          case 0 :
           musiqueDeFond = "Ymca";
           break;
          case 1 :
           musiqueDeFond = "Machine";
           break;
          case 2 :
           musiqueDeFond = "Black";     
           break;
          case 3 :
           musiqueDeFond = "Silence";     
           break;
          case 4 :
           musiqueDeFond = "Bloody";     
           break;
          case 5 :
           musiqueDeFond = "Cannabis";     
           break;
          case 6 :
           musiqueDeFond = "Religion";
           break;
          case 7 :
           musiqueDeFond = "Pongo";     
           break;
          }
         
          nomMusique = TTF_RenderText_Blended(incised_black, musiqueDeFond.c_str(), couleur);
         
          fprintf(configModifie, "NOM1: %s\nNOM2: %s\nMUSIQUEFONDMENU: %s\nNUMEROPISTE: %d", nom1, nom2, musiqueDeFond.c_str(), numMusique);
         
         
          fclose(config);
          fclose(configModifie);
               
          TTF_CloseFont(incised_black);
         
          return nomMusique;
         }
         
        else
         return nomMusique;
    }


    Edit : Vous aurez peut-être besoin de quelques explications ^^

    Si l'on a cliqué sur un des deux boutons, la fonction crée plusieurs variables qui sauvegarderont le contenu du fichier "config.txt". Ensuite, on crée un tableau qui contiendra les chemins relatifs des musiques, on déterminé quelle musique il faut lire, puis on réécrit en actualisant le fichier "config.txt".
    • Partager sur Facebook
    • Partager sur Twitter
    Anonyme
      4 août 2007 à 0:17:16

      Salut,

      a priori, il ne devrait pas y avoir de problème, mais c'est très largement déconseillé de mélanger du C et du C++.

      Si tu as des problèmes avec la gestion des fichiers en C++, regarde dans ma signature, ya un tuto sur les fichiers.

      Xav57
      • Partager sur Facebook
      • Partager sur Twitter
        4 août 2007 à 1:08:06

        1- Aucun gain en temps ou mémoire.
        Gains :
        - Ressource déterministe (i.e. toujours libérée quelque soit le chemin emprunté ; aucun close nécessaire, il est implicite)
        - Typage fort qui évite les erreurs ridicules des printf/scanf ; sans parler ces fonctions C ne sont pas compatibles avec les choses de la SL comme les std::string
        - Pas de limitation dans le nombre de caractères traitables (en restant standard ; i.e. va lire une ligne en C)
        - Liste des types supportés facilement extensible
        - Possibilité de filtrer à volée
        - Possibilité de détourner les I/O vers des trucs que l'on maitrise complètement
        - Uniforminité de gestion pour quantité de types de flux différents (fichier, mémoire, console, et autres types que l'on peut s'écrire: socket, ...)


        2- Les problèmes de compatibilité C <-> C++ peuvent être liés à des mélanges printf/cout & cie. (Plus tous les problèmes que l'on ne peut pas continuer à gérer nos ressources et nos erreurs en C++ comme on le faisait en C, mais ça, c'est une autre histoire)


        Sinon je vois:
        - Des risques de buffer overflow
        - Tu ne testes pas tes I/O
        - Préfères "/" à "\\" pour les chemins des fichiers. Avantages : portable, plus simple à écrire.
        - N'aies pas peur de faire des tableaux constants initialisés lors de leur déclaration ; et de remplacer le switch par un accès dans un tableau.

        • Partager sur Facebook
        • Partager sur Twitter
        C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
          4 août 2007 à 1:50:04

          Citation : Xav57

          Salut,

          a priori, il ne devrait pas y avoir de problème, mais c'est très largement déconseillé de mélanger du C et du C++.

          Si tu as des problèmes avec la gestion des fichiers en C++, regarde dans ma signature, ya un tuto sur les fichiers.



          C'est celui que j'ai lu ;)


          Citation : lmghs


          Sinon je vois:
          - Des risques de buffer overflow
          - Tu ne testes pas tes I/O
          - Préfères "/" à "\\" pour les chemins des fichiers. Avantages : portable, plus simple à écrire.
          - N'aies pas peur de faire des tableaux constants initialisés lors de leur déclaration ; et de remplacer le switch par un accès dans un tableau.



          Merci pour les autres précisions. Par contre là je butte un peu :p
          1°) Buffer overflow ? J'ai déjà entendu le terme mais je vois pas comment ça pourrait m'arriver ici o_O
          2°) Tester les I/O. Euh... Comment on fait ? Ca sert à quoi ? :D
          3°) Mais sous Windows "/" et "\\" sont interprétés de la même manière ?
          4°) Quel intêret ça peut m'apporter ?
          • Partager sur Facebook
          • Partager sur Twitter
            4 août 2007 à 2:08:30

            1- Tu fais un scanf dans un buffer d'un nombre limités d'octets, sans préciser combien tu pouvais vraiment en accepter. Potentiellement, plus de caractères que ce que tu voudrais être possible pourraient être saisis, et corrompre ta mémoire et ton programme.

            2- Ben teste le résultat de ton scanf. Cela te permettra de savoir si la lecture s'est bien passée. Quand ça plante, c'est bien de savoir où.

            3- A part par quelques fonctions oui. Les I/O standard du C et du C++ comprennent parfaitement bien le "/". Toutesfois, je crois qu'il y a des subtilités avec des API propriétaires

            4- Plein de choses
            4.1- éviter de planter parce que tes suppositions ne sont pas valides chez un gars qui a installé ton jeu dans un répertoire dont le nom fait bien 2000 caractères de longs. Ou parce que le fichier est corrompu

            4.2- Etre sûr que tu décodes correctement ce que tu crois impensable d'être indécodable -- surtout qu'il suffit qu'un utilisateur édite le fichier à la main pour le corrompre en oubliant un caractère dans un champ, et là ... c'est la cata.
            Sans parler des problèmes plus vicieux de fin de lignes *nix vs dos.


            4.3- Ai-je vraiment besoin préciser l'intéret de la portabilité à qelqu'un qui fait des tar sous windows ? Surtout que l'on ne sait pas si ton utilisateur bosse sous windows, ou linux, ou macOS X, .... Tu n'as jamais précisé les plateformes/compilos des divers gens utilisant ton code.
            • Partager sur Facebook
            • Partager sur Twitter
            C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
              4 août 2007 à 7:03:54

              Ce sujet à été soulevé des millions de fois depuis la création de la SL : printf vs cout... les flux C++ remporte haut la mains car ils ont été créer pour évités plusieurs pièges du C où tout était un immense tout et peu dynamique.

              en C on fait comme ça, en C++ on utilise nos outils

              Au passage :

              if( /*coordonnées des boutons*/ )
              {
                  //...
                  return nomMusique;
              }
              else
                  return nomMusique;


              C'est pas un peu redondant et inutile? Ce n'est pas important mais c'est beaucoup plus beau, propre et crédible... enfin c'est ma conception d'un travail bien fait, ce n'est pas nécessairement universel ;)
              • Partager sur Facebook
              • Partager sur Twitter
                4 août 2007 à 13:46:23

                Citation : lmghs

                1- Tu fais un scanf dans un buffer d'un nombre limités d'octets, sans préciser combien tu pouvais vraiment en accepter. Potentiellement, plus de caractères que ce que tu voudrais être possible pourraient être saisis, et corrompre ta mémoire et ton programme.

                2- Ben teste le résultat de ton scanf. Cela te permettra de savoir si la lecture s'est bien passée. Quand ça plante, c'est bien de savoir où.



                Ok donc si j'ai bien compris, c'est un problème résolu avec la méthode C++ ? Puisque je remplace mes tableaux dont la taille est définie par avance par des string.


                Citation : MatteX


                Au passage :

                if( /*coordonnées des boutons*/ )
                {
                    //...
                    return nomMusique;
                }
                else
                    return nomMusique;



                C'est pas un peu redondant et inutile? Ce n'est pas important mais c'est beaucoup plus beau, propre et crédible... enfin c'est ma conception d'un travail bien fait, ce n'est pas nécessairement universel &#59;&#41;



                En fait, dans la fonction principale du menu, j'ai un SDL_Surface* qui contient le nom de la musique à afficher entre les deux boutons. Et je dis qu'en cas de clic droit, on appelle la fonction changerMusique de cette manière : nomMusique = changerMusique([...], nomMusique). S'il y a eu clic sur les boutons, nomMusique sera modifié, mais si le clic n'a pas eu lieu sur les boutons, alors il ne sera pas modifié et le return contiendra le nomMusique initial.
                • Partager sur Facebook
                • Partager sur Twitter
                  4 août 2007 à 14:06:45

                  Oui enfin dans tous les cas tu retourneras nomMusique. MatteX a raison, c'est inutile ;)
                  • Partager sur Facebook
                  • Partager sur Twitter

                  Lire dans un fichier

                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                  × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                  • Editeur
                  • Markdown