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 :

Bug de la mort qui tue: l'écriture fantome


Sujet :

C++

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 19
    Points : 15
    Points
    15
    Par défaut Bug de la mort qui tue: l'écriture fantome
    Bonjour à tous. Je viens poster ici car je suis confronter à un bug d'un autre monde. Mais d'abord place au code:
    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
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    #include <iostream>
    #include <fstream>
    #include <string>
     
    using namespace std;
     
    int solution[81];
    bool visible[81];
     
    char mask1 = 1 << 7;
    char mask8 = 1;
     
    unsigned char convertToByte(int value)
    {
    	unsigned char byte = 0;
    	for (int temp = 0; temp < 4; temp++)
    	{
    		if (value % 2)
    		{
    			byte |= mask1;
    		}
    		byte >>= 1;
    		value /= 2;
    	}
    	byte <<= 1;
    	return byte;
    }
     
    int main(int argc, char **argv)
    {
    	std::ifstream input(argv[1]);
    	std::ofstream output(argv[2]);
    	if (input.fail())
    	{
    		cout << "File \"" << argv[1] << "\" not found.\n";
    	}
    	while (!input.eof())
    	{
    		std::string lineV, lineS;
    		input >> lineV;
    		input >> lineS;
    		if (lineV.size() == 0 || lineS.size() == 0)
    		{
    			break;
    		}
    		unsigned char bufferTemp = 0;
    		char buffer = 0;
    		int byteCount = 0;
    		int count = 0;
    		for (int temp = 0; temp < 81; temp++)
    		{
    			if (count == 26)
    			{
    				return 0;
    			}
    			if (count >= 23)
    			{
    				cout << "buffer = " << (int)buffer << "\nbytecount = " << byteCount << "\n";
    			}
    			visible[temp] = (lineV[temp] != '.');
    			char charTemp;
    			charTemp = lineS[temp];
    			solution[temp] = atoi(&charTemp);
    			if (count >= 23)
    			{
    				cout << "J\'ajoute " << solution[temp] << "\n";
    			}
    			bufferTemp = convertToByte(solution[temp]);
    			if (count >= 23)
    			{
    				cout << "\tQui en byte donne : " << (int)bufferTemp << "\n";
    			}
    			if (visible[temp])
    			{
    				bufferTemp |= (mask8 << 3);
    			}
    			if (count >= 23)
    			{
    				cout << "\tApres byte de visibilite on a : " << (int)bufferTemp << "\n";
    			}
    			buffer |= (bufferTemp >> byteCount);
    			if (count >= 23)
    			{
    				cout << "\tApres decalage : " << (int)buffer << "\n";
    			}
    			byteCount += 5;
    			if (byteCount >= 8)
    			{
    				if (count >= 23)
    				{
    					cout << "\tJ\'ecrit : " << (int)buffer << "\n\t c'est le chiffre " << count + 1 << "\n";
    				}
    				//output.seekp(count);
    				output.write(&buffer, 1);
    				count++;
    				buffer = 0;
    				byteCount -= 8;
    				buffer |= (bufferTemp << (5 - byteCount));
    			}
    		}
    		//output.seekp(count);
    		output.write(&buffer, 1);
    	}
    	input.close();
    	output.close();
    	return 0;
    }
    Voila donc mon programme. Son but est simple, encoder une grille de Sudoku avec le minimum de place. Une grille est représentée par deux ligne ASCII, la premiere presente les chiffres visibles ou un point si cachés. La seconde la grille complete.
    Je parse donc mon fichier et j'encode chaque chiffre sur 5 bites, 4 pour le chiffre et 1 pour savoir s'il est visible ou non.
    Jusque la tout marche nickel mais pour cette exemple je suis confronté a un bug qui dépasse ma compréhension. Pour la grille suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    48....2..2..43..1..1.7...93....7.3...9..1.......2.6......32...13..9.8.2...8..1...
    483169275279435816615782493162874359894513762537296148946327581351948627728651934
    pour le 38ieme chiffre on a un 9 visible suivit d'un 4 et un 5 caché. Le 9 ne permet pas de remplir un octet, donc rien n'est ecrit dans cette boucle. à la boucle suivante, on complete avec une partie des bites du 4 et on ecrit l'octet correspondant au caractere 77. il reste alors dans le buffer 3 bites.
    Attention la magie arrive. Au tour d'apres, je prend les 5 bites du chiffre 5 ce qui fait 8 et j'ecrit mon octet. il s'agit du caractere 10. Or si on regarde le fichier resultat, il a ecrit un octet en plus juste avant. Ce dernier ne viens de nul part, completement incroyable. Apres le reste continue normalement mais un octet est venu s'inserer par magie.

    Si quelqu'un peu m'expliquer pourquoi, je lui en serrai eternellement reconnaissant :p.

    Pour exécuter ce code, il suffit de mettre en premier argument un fichier texte avec les chiffres des grilles collés dedans et en 2ieme argument le fichier de sortie

  2. #2
    Membre éclairé

    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    717
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 717
    Points : 858
    Points
    858
    Par défaut
    Je ne sais pas si cela vient de là mais ici
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    			char charTemp;
    			charTemp = lineS[temp];
    			solution[temp] = atoi(&charTemp);
    il y a une erreur : atoi() prend une chaine de caractère (donc terminée par un '\0'), pas un pointeur sur un simple char.

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 19
    Points : 15
    Points
    15
    Par défaut
    Citation Envoyé par Sylvain Togni Voir le message
    Je ne sais pas si cela vient de là mais ici
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    			char charTemp;
    			charTemp = lineS[temp];
    			solution[temp] = atoi(&charTemp);
    il y a une erreur : atoi() prend une chaine de caractère (donc terminée par un '\0'), pas un pointeur sur un simple char.
    Merci pour cette erreur, je l'ai corrigé en remplacant par:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    	char charTemp[2];
    	charTemp[0] = lineS[temp];
    	charTemp[1] = '\0';
    	solution[temp] = atoi(charTemp);
    Mais bon, ca n'a pas changé le bug, j'ai toujours la même chose à la sortie :p

    PS: Si vous avez des questions sur le code n'hésitez pas, j'avoue qu'il est un peu obscure par moment, et je mon anglais n'ettant pas parfait, quand j'ai appelé certaine variable byte quelque chose, c'est bit qu'il faut comprendre, byte = octet en anglais :p

  4. #4
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Quelques remarques :
    - On n'utilise pas eof ainsi pour lire un fichier. http://cpp.developpez.com/faq/cpp/?p...s#FICHIERS_eof
    - Quand tu fais std::ofstream output(argv[2]);, tu ouvres le fichier en mode texte, ce qui fait qu'il va interpréter certains caractères (fin de ligne, par exemple). Pour l'ouvrir en binaire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    	std::ofstream output(argv[2], ios_base::binary);
    - Pour écrire un seul octet, autant utiliser output.put(c); plutôt que output.write(&c, 1);
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 19
    Points : 15
    Points
    15
    Par défaut
    Merci de toutes ces remarques, je débute un peu en C++. Par contre même avec la fonction put(), le resultat est le même, j'ai un chiffre (octet) magique qui viens s'inserer dans mon fichier entre le 24ieme et le 25ieme octet écrit :p
    Et ça, ca defie les lois de l'informatique lol...

  6. #6
    Membre expérimenté Avatar de 10_GOTO_10
    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    886
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 886
    Points : 1 526
    Points
    1 526
    Par défaut
    Citation Envoyé par Fylen Voir le message
    une partie des bites (...) Son but est simple, encoder une grille de Sudoku
    En informatique, on préfère parler de bits

    Citation Envoyé par Fylen Voir le message
    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
    unsigned char convertToByte(int value)
    {
    	unsigned char byte = 0;
    	for (int temp = 0; temp < 4; temp++)
    	{
    		if (value % 2)
    		{
    			byte |= mask1;
    		}
    		byte >>= 1;
    		value /= 2;
    	}
    	byte <<= 1;
    	return byte;
    }
    Je pense qu'il aurait été plus simple d'écrire ceci (équivalent, sauf erreur. J'ai pas vérifié) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    unsigned char convertToByte(int value)
    {
    	return (unsigned char) ((value & 0x0F) << 4);
    }

  7. #7
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par Fylen Voir le message
    Merci de toutes ces remarques, je débute un peu en C++. Par contre même avec la fonction put(), le resultat est le même, j'ai un chiffre (octet) magique qui viens s'inserer dans mon fichier entre le 24ieme et le 25ieme octet écrit :p
    Et ça, ca defie les lois de l'informatique lol...
    Tu as essayé mes autres modifications ? Pour info, quand j'applique le seconde, le fichier généré fait un octet de moins...
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 19
    Points : 15
    Points
    15
    Par défaut
    Merci à tous pour vos reponses, alors en fait la solution était en effet d'ouvrir le fichier en binaire.
    Maintenant, histoire de pas mourir idiot, j'aimerai bien savoir pourquoi?
    Pourquoi ouvrir un fichier en mode texte ajoute un octet quelque part dans le fichier resultat? Je passe la topic en solution trouvé mais j'aimerai bien savoir pourquoi :p

  9. #9
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    À cause de la convention des fichiers texte sous DOS et Windows: Chaque ligne se termine avec les caractères Carriage Return (CR, \r) et Line Feed, aussi appelé New Line (LF, \n).

    La norme C impose que les lignes soit terminées seulement par un \n, donc quand un fichier est ouvert en mode texte, une conversion est faite entre \n et \r\n, dans les deux sens.

    C'est aussi pourquoi dans le cas de fichiers ouverts en mode texte, la fonction fseek() fait l'objet de restrictions.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  10. #10
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 19
    Points : 15
    Points
    15
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    À cause de la convention des fichiers texte sous DOS et Windows: Chaque ligne se termine avec les caractères Carriage Return (CR, \r) et Line Feed, aussi appelé New Line (LF, \n).

    La norme C impose que les lignes soit terminées seulement par un \n, donc quand un fichier est ouvert en mode texte, une conversion est faite entre \n et \r\n, dans les deux sens.

    C'est aussi pourquoi dans le cas de fichiers ouverts en mode texte, la fonction fseek() fait l'objet de restrictions.
    Haaaaaaa merci mille fois, grace à toi j'ai enfin compris, en fait il s'avere que par le plus grand des hazard, le byte ecrit correspond au LF. Du coup il me rajouté un CR avant dans mon fichier d'ou l'erreur. Merci encore ^^

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [2005] BROKER Technique de la mort qui tue (ou pas?!)
    Par Sergejack dans le forum Développement
    Réponses: 1
    Dernier message: 28/04/2011, 17h22
  2. le bug de la mort !
    Par Ekimasu dans le forum Général JavaScript
    Réponses: 6
    Dernier message: 14/12/2005, 16h00

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