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 :

malloc & characteres speciaux


Sujet :

C

  1. #21
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Et puis surtout, un programme n'est pas toujours aussi simpliste. Quand il tourne pendant un moment, parfois des heures ou jours, de nombreuses allocations peuvent se faire pour du traitement, si tu ne libères pas au fur et à mesure que tu n'en a plus besoin, un moment donné l'os n'aura plus de mémoire disponible à te prêter.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  2. #22
    Membre averti
    Avatar de Sparky95
    Homme Profil pro
    Full Stack (web) developer
    Inscrit en
    Décembre 2016
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : Belgique

    Informations professionnelles :
    Activité : Full Stack (web) developer
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2016
    Messages : 379
    Points : 358
    Points
    358
    Par défaut
    ça va merci beaucoup à vous tous pour l'aide et le support apporté
    je vous recontacterai si j'ai d'autre questions sur les alloc

  3. #23
    Membre expérimenté
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    543
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 543
    Points : 1 745
    Points
    1 745
    Par défaut
    Bonsoir,
    Je vais rebondir sur ce que @Sve@r a avancé. Pour faire simple, il n’est nul par écrits dans la norme qu’à la fin du programme la désallocation se fait automatiquement ou que le système d’exploitation se charge de désallouer la mémoire de façon automatique et ceux que l’on soit sous un système d’exploitation ancien ou nouveau. Si c'était le cas, cela serait précisé dans la norme en remplaçant « The lifetime of an allocated object extends from the allocation until the deallocation » par « The life of an allocated object extends from the allocation to the de-allocation, termination or end of the program. »

    Donc, si vous allouez de la mémoire, vous devez la désallouer avant que votre programme se termine. Si vous ne faites pas cela, votre programme ne respecte donc pas la norme et n’est pas portable.
    à bientôt
    Celui qui peut, agit. Celui qui ne peut pas, enseigne.
    Il y a deux sortes de savants: les spécialistes, qui connaissent tout sur rien,
    et les philosophes, qui ne connaissent rien sur tout.
    George Bernard Shaw

  4. #24
    Membre averti
    Avatar de Sparky95
    Homme Profil pro
    Full Stack (web) developer
    Inscrit en
    Décembre 2016
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : Belgique

    Informations professionnelles :
    Activité : Full Stack (web) developer
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2016
    Messages : 379
    Points : 358
    Points
    358
    Par défaut
    Oui mais du coup dois-je désallouer dans le cas ou l'utilisateur nous fait une petite interruption sauvage?
    Ou non pas besoin?
    Je parles ici dans l'étique d'un programme propre

  5. #25
    Membre averti
    Avatar de Sparky95
    Homme Profil pro
    Full Stack (web) developer
    Inscrit en
    Décembre 2016
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : Belgique

    Informations professionnelles :
    Activité : Full Stack (web) developer
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2016
    Messages : 379
    Points : 358
    Points
    358
    Par défaut
    autre petite question rapide pour éviter d'ouvrir une nouvelle discussion

    Citation Envoyé par souviron34 Voir le message
    c'est pourtant simple et on l'a répété 250000 fois sur ce forum..
    • FEOF NE S'UTILISE PAS COMME CA
    • ON NE TESTE PAS LA FIN DE LECTURE COMME CA....
    Je lis ici qu'il "engueule" une personne car elle a fait une boucle lecture fichier avec en condition de sortie feof(fichier).
    Pourquoi n'est-ce pas bon?
    surtout qu'ici cela est fait en exemple dans le cours sur la lecture et écriture dans les fichiers

  6. #26
    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
    souviron34 engueulait tout le temps tout le monde (je l'aimais bien lui....) et pour le coup il avait raison. Regarde cette entrée de la FAQ qui explique bien pourquoi : https://c.developpez.com/faq/?page=E...-fonction-feof Ce cours que tu montres n'est pas tout à fait juste, ou plutôt il fait un raccourci. En fait, cette méthode fonctionne tant que ta lecture n'échoue pas et que tu atteints sans encombre la fin du fichier. Et tu viens par la même occasion (mais tu l'avais déjà peut-être compris avec cette histoire de libération de la mémoire) que le C n'est pas un langage facile, avec beaucoup de petites choses que plusieurs personnes n'ont pas interprété de la même manière.... ou pas avec la même rigueur.

  7. #27
    Membre averti
    Avatar de Sparky95
    Homme Profil pro
    Full Stack (web) developer
    Inscrit en
    Décembre 2016
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : Belgique

    Informations professionnelles :
    Activité : Full Stack (web) developer
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2016
    Messages : 379
    Points : 358
    Points
    358
    Par défaut
    Je n'ai pas trop compris cette partie de code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
            if (feof(fp)) 
            { 
                printf("Fin de fichier atteinte !\n"); 
                printf("La taille du fichier est : %ld octets.\n", taille); 
            } 
            else 
            { 
                if (ferror(fp)) 
                    printf("Arret du programme en raison d'une erreur de lecture !\n"); 
            }
    This function returns a non-zero value when End-of-File indicator associated with the stream is set, else zero is returned.
    Car sur ce site il est mis si je ne me trompes pas: cette fonction retourne une val !0 lorsqu'on arrive à la fin sinon un 0.

    Du coup while (!feof(Fich)) ferrait un tour de boucle de trop vu qu'il arrive a la fin du fichier mais la valeur est !0 et donc il continue jusqu’à arriver à l'erreur?
    est-ce bien ça?

    du coup je devrais plutot faire ma fonction comme ceci?
    basé sur https://www.geeksforgeeks.org/eof-and-feof-in-c/
    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
    struct index* LoadUsers(FILE *fichier)
    {
    	struct index tmpIndex, *start = NULL, *new = NULL;
    	bool erreur = false;
    	fread(&tmpIndex.user, sizeof(tmpInde.user, 1, fichier);
     
    	if(tmpIndex.user != EOF){
    		start = (struct index*)malloc(sizeof(tmpIndex));
     
    		if(start){
    			if(DEBUG) printf("Malloc créé: adresse: %d\n", start);
     
    			//fread(&start->user, sizeof(tmpIndex.user), 1, fichier);
    			//fscanf(fichier, "%d/%d %s %s", &start->user.server, &start->user.id, start->user.pseudo, start->user.pseudo_ingame);
    			*start = tmpIndex;
    			start->suivant = NULL;	
     
    			while(!erreur && fread(&tmpIndex.user, sizeof(tmpInde.user, 1, fichier) != EOF){
     
    				new = (struct index*)malloc(sizeof(tmpIndex));
    				if(DEBUG) printf("Malloc créé: adresse: %d\n", new);
     
    				if(new){
     
    					//fread(&new->user, sizeof(tmpIndex.user), 1, fichier);
    					//fscanf(fichier, "%d/%d %s %s", &new->user.server, &new->user.id, new->user.pseudo, new->user.pseudo_ingame);
    					*new = tmpIndex;
    					new->suivant = NULL;	
    					InsertUser(start, new);
    				}else{
    					printf("erreur lors de mise en mémoire\n");
    					erreur = true;
    				}
    			}
    		}else
    			printf("erreur lors de la création de mise en mémoire\n");
    	}else
    		printf("fichier vide\n");
    	return start;
    }
    J'imagine que je ne peux pas faire ça car EOF retournes un character or mon index.user attends un int est bien ça?
    comment pourrais-je le faire autrement?
    j'airais comme idée lire un char pour retourner un cran en arriere mais bon c'est pas super niveau optimisation :s

  8. #28
    Membre expérimenté
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    543
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 543
    Points : 1 745
    Points
    1 745
    Par défaut
    Si je peux me le permettre, je pense qu'il faut peut-être mettre à jour la FAQ sauf erreur de ma part (dans ce cas mes excuses par avance).
    Il est écrit dans la FAQ que "la fonction feof() ne sert pas à détecter la fin d'un fichier, mais, lorsqu'une lecture a échoué, à savoir si cet échec est dû à la rencontre de la fin de fichier.
    "
    . Hors que, feof() ne sert pas non plus a ça, il renvoie une valeur non-nulle si et seulement si l'indicateur de fin de fichier pour le flux "X" est activé. En d'autres termes feof(), renvoie une valeur qui est non-nulle si la fin du fichier associée au flux "X"a été atteinte lors d'une lecture précédente. Pour détecter les erreurs, il faut utiliser ferror qui renvoie une valeur non-nulle si et seulement si l'indicateur d'erreur pour le flux de x est défini/activé, indiquant qu'une erreur s'est produite lors d'une opération précédente sur le flux en plus clair si l'opération de lecture/ecriture a été faite ferror va tester si l'opération effectuée sur le flot en question à générée une erreur ou non; en cas d'erreur, ferror retourne l'indicateur d'erreur/la valeur non-nulle qui correspond à l'erreur a ceci prés que l'indicateur d'erreur reste actifs même-ci une l'on effectue une autre opération réussie; pour levée cette erreur, il faut donc procéder a la mano au désengagement de l'indicateur d'erreur en utilisant la fonction clearerr.

    Ceci dit, le code proposé dans la FAQ comporte une erreur non-détectable dû non pas à un mauvais emploi de la fonction feof()/ferror(), mais plutôt a un mauvais contrôle de flux puisque dans les faits, si l'on a une erreur dans la boucle de traitement exemple une instruction parasite (void)fputc('A',fp); (voir autres) l'erreur ne sera pas détectée, et ce, tout simplement parce que ferror() est en dehors de la boucle. Normalement si elle est placée dans la boucle vous deviez avoir comme du style erreurs (8) bad descriptor.
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
     
    #include <stdio.h>
    #include <stdlib.h>
     
    int main(void) 
    { 
        FILE * fp = fopen("source.c", "rb"); 
     
        if (fp == NULL) 
            fprintf(stderr, "La fonction fopen a echoue.\n"); 
        else 
        { 
            int c; 
            long taille = 0; 
     
            while ((c = fgetc(fp)) != EOF) 
            { 
                /* Utilisation du caractère lu.                  */ 
                /* Dans notre cas, on n'en a rien à faire.       */ 
                /* On incrémente tout simplement notre compteur. */ 
                if (ferror(fp)) 
                    printf("Arret du programme en raison d'une erreur de lecture !\n"); 
     
                taille++; 
     
                /*
                *   /!\ INJECTION /!\
                *   detection d'erreurs impossible
                */
                fputc('A', fp );
            } 
     
            if (feof(fp)) 
            { 
                printf("Fin de fichier atteinte !\n"); 
                printf("La taille du fichier est : %ld octets.\n", taille); 
            } 
            else 
            { 
                if (ferror(fp)) 
                    printf("Arret du programme en raison d'une erreur de lecture !\n"); 
     
                /*
                * Autre erreur, il faut un désengagement de l'indicateur d'erreur 
                * en utilisant la fonction X cas contraire l'erreur est toujours 
                * actifs & faire une sorti contrôler.
                */
                clearerr(fp);
                return EXIT_FAILURE;
            } 
        } 
     
        return 0; 
    }

    Autres point plus important en passant qu'il faut tout de même mentionner. Il faut faire attention à l'emploi d'EOF sur les fichiers sous un système d'exploitation de type GNU/Linux. Tout simplement parce que sous GNU/Linux, les fichiers sont en réalité considérés comme binaire.

    Très souvent, les diverses raisons de la difficulté de l’emplois des fonctions feof()/ferror() sont dues à comment doit-on placer les fonctions pour contrôler, sortir/détecter les erreurs de flux dans la boucle, c'est-à-dire la façon/le moyen le plus évident d'utiliser feof()/ferror() pour contrôler une boucle/detecter des erreurs voir les deux. S'il faut réécrire dans un premier temps l'ensemble de ce que j'avance cela s'apparenterais au code source-ci dessous, mais attention, c'est un exemple il peut donc y avoir des erreurs surtout qu'il y a une autre façon d'écrire les instructions.
    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
    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
     
    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
     
     
    int main( void ) {                                                                        
     
          int ret = 0;                                                            
          FILE *p = NULL;                                                             
     
          /*
          *	Ouverture du fichier
          */
          if( NULL == ( p= fopen("source.c", "r") ) ){
          	(void)fprintf(stderr, 
          		"(%d)Erreur\t: ouverture de fichier\n\t:%s\n",
          		errno, strerror(errno) );
          	return EXIT_FAILURE;
          }
     
          /*
          *	traiment
          */
     
          errno = 0;
          for(;;){
          	ret = fgetc(p);
          	if( EOF == ret ){
          		if( feof(p) ){
          			(void)fprintf(stderr,
          				"\nfin de flux\n" );
          			/*
          			* Utilisation de abort(), dont, le traitement dépendra 
          			* du système d'exploitation hôte.
          			*/
          			if( EOF != fclose(p) ){
    	      			p = NULL;
    	      			return EXIT_SUCCESS;
          			}
          			(void)fprintf(stderr,
          				"Erreur critique close file impossible\n");
          			/*
    				* Cependant abort déclenche un arrêt brutale et volontaire 
    				* du programme avec un signal SIGABRT dû a l'échec de la 
    				* fonction fclose cela est probablement dû a une erreur liée 
    				* a des erreurs sous-jacentes du système d'exploitation 
    				* qui ne peut être contournée.
    				*/
     
          			abort(); //
     
          		}
          	}
     
          	/*
          	*	detection d'erreurs
          	*/
          	if( ferror(p) ){
          		(void)fprintf(stderr, 
          			"(%d)Erreur\t:%s\n", errno,
          			strerror(errno) );
          		clearerr(p);
          		return EXIT_FAILURE;
          	}
     
          	(void)fprintf(stderr, "%c",
          		ret );
     
          	/*
          	* Dé-comenter si vous souhaitez 
          	* générer une erreur l'instruction ci-dessous
          	*/
     
          	//(void)fputc('A', p );
          }
     
          // Instruction jamais atteinte
          return EXIT_FAILURE;
    }

    @Sparky95: Pour répondre à votre question, si vous prenez en compte le SIGINT (CTRL+C) alors vous devez vous assurerez de désallouer la mémoire allouée cas contraire, le système hôte se chargera de prendre les mesure nécessaire. Personnellement, je vous le déconseille. Laisser le gestionnaire par défaut faire sont travail.
    Il faut juste comprendre ceci ; un programme qui se termine n'a pas de fuites mémoire. Seul un programme en cours d'exécution peut avoir des fuites mémoires. Une fois que le programme sort, toute la mémoire est libérée ou réattribue, mais il faut respecter tout de même la norme et les règles de portabilité ; un malloc = un free = respect de la norme = programme portable.
    à bientôt.
    Celui qui peut, agit. Celui qui ne peut pas, enseigne.
    Il y a deux sortes de savants: les spécialistes, qui connaissent tout sur rien,
    et les philosophes, qui ne connaissent rien sur tout.
    George Bernard Shaw

  9. #29
    Membre averti
    Avatar de Sparky95
    Homme Profil pro
    Full Stack (web) developer
    Inscrit en
    Décembre 2016
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : Belgique

    Informations professionnelles :
    Activité : Full Stack (web) developer
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2016
    Messages : 379
    Points : 358
    Points
    358
    Par défaut
    @sambia39 ça va merci beaucoup par-contre je dois vous avouer que vous m'avez perdu des le début des explications
    Je n'ai compris que la fin des explications à partir du moment ou vous m'expliquez les fuites mémoires

  10. #30
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    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 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par sambia39 Voir le message
    Pour faire simple, il n’est nul par écrits dans la norme qu’à la fin du programme la désallocation se fait automatiquement ou que le système d’exploitation se charge de désallouer la mémoire de façon automatique
    Cela ne pourra jamais être écrit. La norme du C ne peut pas impliquer l'OS...

    Citation Envoyé par Sparky95 Voir le message
    Oui mais du coup dois-je désallouer dans le cas ou l'utilisateur nous fait une petite interruption sauvage?
    Ou non pas besoin?
    Je parles ici dans l'étique d'un programme propre
    Ca dépend. Si tu programmes le coeur d'une centrale nucléaire, ou bien le contrôle du pilote automatique d'un Airbus; alors oui vaudrait mieux que ton programme soit ultra blindé et ultra redondant.
    Si maintenant tu programmes la gestion du carnet d'adresse de la secrétaire ben tu n'es pas obligé d'aller aussi loin...
    Tout est question de compromis entre la criticité de ton programme et le temps passé à le blinder. De mon avis personnel, je pense que la bonne approche (en général) est de considérer que le programme ira jusqu'à la fin et de programmer donc la libération classique et ne pas te préoccuper de l'interruption sauvage ctrl-c (où tu as quand-même de grandes chances que ce soit alors géré par l'OS).

    Citation Envoyé par Sparky95 Voir le message
    Du coup while (!feof(Fich)) ferrait un tour de boucle de trop vu qu'il arrive a la fin du fichier mais la valeur est !0 et donc il continue jusqu’à arriver à l'erreur?
    est-ce bien ça?
    Exact. Quand tu lis le dernier caractère, l'OS ne sait pas encore que c'est le dernier. C'est quand tu tentes de lire après ce dernier que là, la fonction de lecture échoue et que le flag "End Of File" est levé.

    Accessoirement, si tu réfléchis bien, nous aussi nous fonctionnons ainsi. Quand on lit un texte, et qu'on arrive au dernier mot de la dernière ligne, on ne peut pas à priori savoir qu'on est sur ce dernier mot. C'est en analysant la phrase lue, et aidé de la ponctuation, qu'on détecte alors que c'était la fin. C'est certes un mécanisme extrèmement rapide et presque instantané que fait ton cerveau; mais c'est quand-même une action qui peut s'apparenter à "on essaye de lire après pour alors comprendre qu'il n'y a plus rien à lire".

    Donc pour l'ordi, c'est pareil. Il s'ensuit que ce type de traitement...
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    char c;
    while (!feof(fp)) {
    	c=lecture(fp)
    	traitement c
    }
    ... ne fonctionne pas car tu lis le dernier caractère, tu traites le dernier caractère, le flag End Of File n'est pas levé, feof() renvoie 0, tu tentes alors de lire après le dernier caractère, la fonction échoue mais tu traites quand-même la variable "c" (qui, n'ayant pas été modifiée, contient toujours le caractère de la lecture précédente). Bref tu traites deux fois le dernier caractère.

    Pour résoudre, tu corriges en testant la lecture ce qui donne
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    char c;
    while (!feof(fp)) {
    	if ((c=lecture(fp)) == valeur_speciale_indiquant_que_la_lecture_ne_s_est_pas_faite) break;
    	traitement c
    }

    Ok, là ça fonctionne. Mais là, ton oeuil d'aigle examine ce code et constate alors que ça peut se simplifier en
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    char c;
    while ((c=lecture(fp)) != valeur_speciale_indiquant_que_la_lecture_ne_s_est_pas_faite)
    	traitement c
    }
    Et du coup, feof() n'a plus de raison d'être (ce qui est normal puisque son rôle n'est pas de détecter la fin de fichier). Certes rien ne t'interdit de l'utiliser (comme dans mon second exemple) tout comme rien ne t'interdit d'utiliser une perceuse pour planter un clou, mais dans les deux cas tu te compliques la vie en n'utilisant pas les outils adaptés au but à atteindre.

    Citation Envoyé par Sparky95 Voir le message
    J'imagine que je ne peux pas faire ça car EOF retournes un character or mon index.user attends un int est bien ça?
    comment pourrais-je le faire autrement?
    Euh... Je ne suis pas certain de bien saisir la phrase "EOF retourne un caractère". EOF c'est une valeur spéciale (qui doit probablement valoir -1) et qui est renvoyée quand la fonction de lecture échoue. EOF ne peut donc rien retourner.
    Tel que je lis ton code (tant que lecture ne retourne pas EOF) ça me semble bon. Si le fread() se fait alors il charge tmpIndex.user avec l'int lu ; et s'il ne peut pas se faire, alors d'une part il ne remplira pas tmpIndex.user (qui restera alors inchangé de la lecture précédente) et d'autre part il renverra la valeur EOF que tu détecteras et sortiras de la boucle...
    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]

  11. #31
    Membre averti
    Avatar de Sparky95
    Homme Profil pro
    Full Stack (web) developer
    Inscrit en
    Décembre 2016
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : Belgique

    Informations professionnelles :
    Activité : Full Stack (web) developer
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2016
    Messages : 379
    Points : 358
    Points
    358
    Par défaut
    cv merci beaucoup pour ces explications le feof et EOF n'étaient que des notions vues pour moi :p


    Citation Envoyé par Sve@r Voir le message
    Euh... Je ne suis pas certain de bien saisir la phrase "EOF retourne un caractère". EOF c'est une valeur spéciale (qui doit probablement valoir -1) et qui est renvoyée quand la fonction de lecture échoue. EOF ne peut donc rien retourner.
    Tel que je lis ton code (tant que lecture ne retourne pas EOF) ça me semble bon. Si le fread() se fait alors il charge tmpIndex.user avec l'int lu ; et s'il ne peut pas se faire, alors d'une part il ne remplira pas tmpIndex.user (qui restera alors inchangé de la lecture précédente) et d'autre part il renverra la valeur EOF que tu détecteras et sortiras de la boucle...
    J'avais mal compris le EOF

    et je me référais à ceci ceci

  12. #32
    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
    @sambia39 : ergoter (en plus face à un débutant) avec des trucs délirants, ça devient une habitude à laquelle il faudrait faire attention



    Ah et dans le cas présent je me demande même si ce n'est pas faux en plus... En effet, je suis sceptique de voir que ton deuxième code ne semble pas détecter plus d'erreur que le premier. Et j'ai bien décommenté la ligne...

  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 689
    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 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Ah et dans le cas présent je me demande même si ce n'est pas faux en plus... En effet, je suis sceptique de voir que ton deuxième code ne semble pas détecter plus d'erreur que le premier. Et j'ai bien décommenté la ligne...
    Je suis assez d'accord (tout à l'heure j'avais pas trop décortiqué ce qu'il avait écrit)

    @sambia: je pense que dans ce code

    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
    while ((c = fgetc(fp)) != EOF) { 
    	/* Utilisation du caractère lu.                  */ 
    	/* Dans notre cas, on n'en a rien à faire.       */ 
    	/* On incrémente tout simplement notre compteur. */ 
    	if (ferror(fp)) 
    		printf("Arret du programme en raison d'une erreur de lecture !\n"); 
     
    	taille++; 
     
    	/*
    		*   /!\ INJECTION /!\
    		*   detection d'erreurs impossible
    	*/
    	fputc('A', fp );
    }
    Je ne vois pas trop en quoi détecter l'erreur dans la boucle sera mieux que de la détecter en dehors.
    Déjà (je peux me tromper car j'ai pas examiné en détail la doc de ferror()) mais il me semble que cette fonction ne détecte que les erreurs de lecture graves (arrêt du disque, éjection de la clef USB, etc) et non les erreurs du type "je tente d'écrire dans un flux ouvert en lecture" car ce dernier cas est alors remonté par le retour de fputc() (qui vaut alors -1) et errno qui se positionne sur la cause de l'erreur. Et donc (encore une fois je dis ça sans avoir testé mais juste réfléchi à la logique du truc) ferror() ne détecte rien.

    Donc pour moi, le bon code (c'est à dire fonctionnant sans faire d'opérations inutiles) est le suivant

    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
    while ((c = fgetc(fp)) != EOF) { 
    	/* Utilisation du caractère lu.                  */ 
    	/* Dans notre cas, on n'en a rien à faire.       */ 
    	/* On incrémente tout simplement notre compteur. */ 
    	taille++; 
     
    	/*
    		*   /!\ INJECTION /!\
    		*   detection d'erreurs sur la fonction d'écriture
    	*/
    	if (fputc('A', fp) < 0)
    		fprintf(stderr, "Erreur d'écriture fp - %s\n", strerror(errno));
    }
     
    if (feof(fp))
    	printf("Fichier traité\n");
    elif (ferror(fp))
    	fprintf(stderr, "Fichier incomplètement traité - %s\n", strerror(errno));

    Et encore, j'ai mis elif (ferror(fp)) n'étant pas certain qu'il n'y avait pas une 3° possibilité mais je suis quasiment sûr que le test de fin peut s'écrire plutôt
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if (feof(fp))
    	printf("Fichier traité\n");
    else
    	fprintf(stderr, "Fichier incomplètement traité - %s\n", strerror(errno));

    Ou inversement
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if (ferror(fp))
    	fprintf(stderr, "Fichier incomplètement traité - %s\n", strerror(errno));
    else
    	printf("Fichier traité\n");

    Citation Envoyé par sambia39 Voir le message
    Autres point plus important en passant qu'il faut tout de même mentionner. Il faut faire attention à l'emploi d'EOF sur les fichiers sous un système d'exploitation de type GNU/Linux. Tout simplement parce que sous GNU/Linux, les fichiers sont en réalité considérés comme binaire.
    Je ne vois pas trop le rapport entre "comme quoi est considéré le fichier" et "la valeur retournée par la fonction qui le lit quand elle ne peut plus le lire"...

    Par ailleurs j'ai l'impression à te lire que "considéré comme binaire" c'est être l'exception. Alors que justement les fichiers binaires sont la norme. Ce sont des fichiers dans lesquels "une information" se traduit par "le nombre exact d'octets nécessaires au codage de l'information" (ex un float se traduira par 4 octets parce qu'un float se code sur 4 octets) ; ce qui est tout à fait sensé et logique. Ce sont au contraire les fichiers textes Windows qui sont les débiles. Chez-eux, un caractère informatif peut se traduire par un ou deux caractères physiques (ex le "end of line", qui est bien "un" caractère informatif, qui se traduit par deux caractères physiques '\r' suivi de '\n'). Ce sont bien eux donc qui sont les tarés de la bande. Ce sont eux qui mettent la zone chaque fois qu'on veut programmer un algo générique de traitement de fichier. J'irai même dire que c'est dommage qu'il faille spécifier "b" quand on appelle fopen() parce que ça laisse sous-entendre qu'être binaire c'est être l'exception qui doit se gérer différement. Moi, j'aurais tout considéré par défaut comme binaire et j'aurais programmé la fonction fopen() pour qu'on lui passe "t" quand on veut ouvrir du texte.
    Les fichiers Linux sont des fichiers normaux, basiques, standards ; fichiers dont tous les autres OS devraient prendre exemples.
    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
    Membre expérimenté
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    543
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 543
    Points : 1 745
    Points
    1 745
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Je ne vois pas trop en quoi détecter l'erreur dans la boucle sera mieux que de la détecter en dehors.
    Déjà (je peux me tromper car j'ai pas examiné en détail la doc de ferror()) mais il me semble que cette fonction ne détecte que les erreurs de lecture graves (arrêt du disque, éjection de la clef USB, etc) et non les erreurs du type "je tente d'écrire dans un flux ouvert en lecture" car ce dernier cas est alors remonté par le retour de fputc() (qui vaut alors -1) et errno qui se positionne sur la cause de l'erreur. Et donc (encore une fois je dis ça sans avoir testé mais juste réfléchi à la logique du truc) ferror() ne détecte rien.

    Pour expliquer ce que j'ai écrit, je pars de là:
    (7.21.10.2) : The feof function tests the end-of-file indicator for the stream pointed to by stream. The feof function returns nonzero if and only if the end-of-file indicator is set for stream.
    The ferror function tests the error indicator for the stream pointed to by stream. The ferror function returns nonzero if and only if the error indicator is set for stream.

    Donc, une erreur de fin de fichier et une erreur de lecture peuvent être distinguées et détectées par l'utilisation des fonctions feof et ferror.
    dans le cas du premier code issue a la base du FAQ que j'ai ajouter des instruction.
    1. Le fichier est ouvert en lecture.
    2. L’emploi ou l’appel de la fonction fputc va générer une erreur parce que le fichier est en lecture et non en écriture.
    3. ferror va détecter l’erreur sur le flux du fichier parce que l’appel de la fonction précédente a généré une erreur sur le flux.
    4. Si ont emplois pas la fonction clearerr l’indicateur d’erreur reste actifs et donc le seconde teste de ferror est toujours vrais puisqu’il y a erreur.

    à quel moment ferror détecte l'erreur s'il se trouve hors de la boucle et ce sachant également que l'on a un feof juste avants. Quand est t'il également si feof lis un fichier vide ?

    @Sve@r dans votre code, vous testez bien la tentative d’écrire d’un caractère ( il y'a un garde fou); Si celle-ci échoue elle affiche une erreur, mais si le programme continu son exécution "tout de même" on obtiendrais comme resltats, le message suivants fprintf(stderr, "Erreur d'écriture fp - %s\n", strerror(errno)); en boucle puis viens le teste de fin de fichier qui affichera a son tour "Fichier traité" quand est t'il alors pour le message d’erreur de ferror ?. C’est là ou dans mon dernier message, j’explique que la difficulté ici n’est pas l’emploi des fonction mais ou les placer pour détecter une éventuelle erreur de traitement sur le flux de fichier avant que l’on atteigne la fin du fichier et non après. Tester donc en mettant (2) devant le message d'erreur de ferror et dite moi ce que vous en pensé.

    Citation Envoyé par Sve@r Voir le message
    Je ne vois pas trop le rapport entre "comme quoi est considéré le fichier" et "la valeur retournée par la fonction qui le lit quand elle ne peut plus le lire"...
    Pour répondre à votre question. En ma connaissance sauf erreur de ma part, sur les systèmes tel qu'Unix ou GNU/Linux il n'y a pas vraiment voir/aucun moyen de déterminer le type de fichier sans l'ouvrir ou faire la différence entre un fichier texte simple et un fichier binaire. Le seul moyen est la lecture des octets magique/signature (exemple [4F 67 67 53] pour ogg ou [25 50 44 46] pdf) du fichier ou la lecture d’un certain nombre d’octets et donc par défaut le système d’exploitation considère le/les fichier comme étants binaire. Plus en détails, parce que sur les systèmes d’exploitation Unix ou GNU/Linux leurs systèmes de fichiers ne stocke aucune information permettant de conaître leur contenue et donc faire la distinction, entre un fichier text d’un binaire. La seule prérogative en ma connaissance est l’utilisation des répertoires pour faire une distinction (si je peux dire ainsi) exemple le repertoire /bin/ par exemple, car elle caractérise le format du fichier en question. Et sans vouloir faire des vagues ou en fâché plus d’un. GNU/Linux tout comme Unix utilise rarement les extensions de fichiers.
    Pour plus de détails, je vous invite a lire Filesystem Hierarchy Standard , le diff ou
    Binary Files and Forcing Text Comparisons



    Citation Envoyé par Bktero Voir le message
    @sambia39 : ergoter (en plus face à un débutant) avec des trucs délirants, ça devient une habitude à laquelle il faudrait faire attention

    Ah et dans le cas présent je me demande même si ce n'est pas faux en plus... En effet, je suis sceptique de voir que ton deuxième code ne semble pas détecter plus d'erreur que le premier. Et j'ai bien décommenté la ligne...
    @Bktero: Tout d’abord le premier code, c’est le code qui vient directement du FAQ dans lequel j’ai ajouté le nom du fichier « source.c » à lire, la fonction ferror() dans la boucle de traitement et la fonction clearerr; Je mets l’accent sur le fait que l’on ne détecte pas les erreurs de flux. Quant au seconde, c’est bien mon exemple.
    Deuxième point en quoi j’ai avancé des choses délirante ? Dans ce que j’ai écris à @Sparky95.
    Celui qui peut, agit. Celui qui ne peut pas, enseigne.
    Il y a deux sortes de savants: les spécialistes, qui connaissent tout sur rien,
    et les philosophes, qui ne connaissent rien sur tout.
    George Bernard Shaw

  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
    Encore une fois, tu ne te mets pas au niveau du PO. Il est clair que c'est quelqu'un qui n'est pas très à l'aise avec le C et rentrer dans un tel niveau de pinaillage sur des détails ne peut pas l'aider. Dommage que tu ne t'en rendes pas compte...

    Puisque j'y suis, parlons des extraits de code. Histoire que j'explique au moins pourquoi je pense que c'est faux.

    1) Déjà, il y l'idée de dire que le code la FAQ est faux. Schématiquement ce code donne 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
     
    while ((c = fgetc(fp)) != EOF) 
    { 
        // traitement de c
    } 
     
    if (feof(fp)) 
    { 
        // Fin de fichier atteinte
    } 
    else  if (ferror(fp)) 
    {
        // Erreur rencontrée
    }
    En ouvrant le man de fgetc(), on apprend que fgetc renvoie EOF en cas d'erreur ou de fin de fichier :
    fgetc() reads the next character from stream and returns it as an unsigned char cast to an int, or EOF on end of file or error.
    Il faudra vraiment m'expliquer ce qui est faux dans cette boucle... Si la boucle s'arrêter, c'est qu'on rencontré un de ces deux cas. Le premier se teste avec feof(), le second avec ferror(). On peut se poser la question d'un else et de ce qu'on pourrait y mettre dedans mais ce cas semble hautement improbable.

    2) Ton premier code montre une boucle sur la même condition et le premier truc fait dans la boucle est de regarder ferror(). Mais comment ferror() pourrait bien remonter une erreur puisque fgetc() n'a pas renvoyé EOF (sinon, on ne serait pas dans la boucle, non ? ) et qu'on ne fait aucune opération sur le fichier après ? Là aussi, je ne comprends pas...

    3) Attaquons l'idée d'injecter une soi-disant erreur... Non mais allô ?! On marche sur la tête !!! C'est un code qui lit un fichier pour en déterminer la taille et toi tu te dis "hé regardez si j'écris dedans ça fait n'importe quoi". Non mais tu expliques comment faire de l'électricité et tu dis attention si vous branchez votre système d'arrosage en même temps à l'intérieur de la maison ça va faire des étincelles.

    4) Je passe ton deuxième code avec des trucs qui font mal aux yeux et tue la lisibilité.

    - Ca commence avec la déclaration de la variable FILE* p qu'on initialise à NULL pour ensuite l'affecter à l'intérieur d'un if : tu t'es dit que c'était un exemple pour un débutant un truc aussi moche ?
    - Les cast en (void) des retours de fprintf() pour éviter des vieux warnings utilisés uniquement dans les projets paranoïaques.
    - Les fautes de français dans les commentaires ("traiment" ligne 25)
    - La boucle while(fgetc) qui devient un for(;; avec en prime une variable à la C89 en début de main()
    - La mise à NULL de p inutile car suivi d'un return (ligne 40)
    - L'absence de else parce qu'on a fait un return sauvage si on a réussit à fermer le fichier (ligne 43)
    - Les fprintf() sur 3 lignes de 25 caractères (ligne 62) ou sur 2 lignes pour ne pas dépasser les 40 colonnes (on loin des 80 !!!) (ligne 69). Un stagiaire me montre un code comme ça, je lui demande gentiment d'aller retravailler un peu la mise en forme...
    - Du code mort (enfin, documenté comme mort, j'ai pas pu le vérifier...) (ligne 81)

    5) Enfin, le plus gros quand même. J'ai testé tout à l'heure sous Windows 10 avec mingw64 et ça n'a détecté aucune erreur. Le fputc() a juste fait avant la position dans le fichier et donc le programme m'annonce une taille moins importante que la réalité.....mais ne détecte aucune erreur.

  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 689
    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 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par sambia39 Voir le message
    Donc, une erreur de fin de fichier et une erreur de lecture peuvent être distinguées et détectées par l'utilisation des fonctions feof et ferror.
    Exact. Je viens de tester
    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
    #include <stdio.h>
     
    int main() {
    	FILE *fp;
    	int c;
    	fp=fopen("/etc/passwd", "r");
     
    	while ((c=fgetc(fp)) != EOF)
    		fputc(c, stdout);
    	fputc(c, fp);
    	if (feof(fp)) printf("feof\n");
    	if (ferror(fp)) printf("ferror\n");
    	fclose(fp);
    }
    Effectivement le fputc(c, fp) lève un flag que ferror() détecte. Bon point pour toi je le reconnais car je ne savais pas qu'il allait jusqu'à détecter un truc aussi con que "oups j'ai écrit dans un flux dédié à la lecture".

    Citation Envoyé par sambia39 Voir le message
    à quel moment ferror détecte l'erreur s'il se trouve hors de la boucle et ce sachant également que l'on a un feof juste avants.
    Ben feof() indique si le flag EOF a été levé ; et ferror() indique si le flag "file error" a été levé. Les deux flags ne sont pas exclusifs l'un de l'autre (ce que montre d'ailleurs mon exemple ci dessus)

    Citation Envoyé par sambia39 Voir le message
    Quand est t'il également si feof lis un fichier vide ?
    Ben (avec mon exemple) ça marche aussi => la lecture renvoie EOF donc la boucle ne se fait pas mais le flag EOF est bien levé

    Citation Envoyé par sambia39 Voir le message
    @Sve@r dans votre code, vous testez bien la tentative d’écrire d’un caractère ( il y'a un garde fou); Si celle-ci échoue elle affiche une erreur, mais si le programme continu son exécution "tout de même" on obtiendrais comme resltats, le message suivants fprintf(stderr, "Erreur d'écriture fp - %s\n", strerror(errno)); en boucle puis viens le teste de fin de fichier qui affichera a son tour "Fichier traité" quand est t'il alors pour le message d’erreur de ferror ?
    C'est juste une question de tests. Suffit de changer le test final en ceci
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    if (ferror(fp)) 
    {
        // Erreur rencontrée
    }
    elif (feof(fp)) 
    { 
        // Fin de fichier atteinte
    }
    Ou toute autre construction algorithmique permettant, selon le choix du programmeur, de privilégier le flag EOF, le flag error ou les deux ensembles (encore une fois comme mon exemple en haut de ce post).

    Citation Envoyé par sambia39 Voir le message
    C’est là ou dans mon dernier message, j’explique que la difficulté ici n’est pas l’emploi des fonction mais ou les placer pour détecter une éventuelle erreur de traitement sur le flux de fichier avant que l’on atteigne la fin du fichier et non après. Tester donc en mettant (2) devant le message d'erreur de ferror et dite moi ce que vous en pensé.
    Ben voilà. Je viens de répondre.

    Citation Envoyé par sambia39 Voir le message
    Pour répondre à votre question. En ma connaissance sauf erreur de ma part, sur les systèmes tel qu'Unix ou GNU/Linux il n'y a pas vraiment voir/aucun moyen de déterminer le type de fichier sans l'ouvrir ou faire la différence entre un fichier texte simple et un fichier binaire.
    Exact. Tout simplement parce qu'il n'y en a aucune. Sur Linux on a des fichiers qui contiennent du son, d'autres de la vidéo, d'autres qui contiennent des images, et d'autres qui contiennent des caractères ascii. Pour ces derniers il se trouve que les éditeurs les affichent bien proprement parce que ces fichiers indiquent, en plus du code ascii lisible, un caractère particulier spécifiant "ici on passe sur une autre ligne" que ces mêmes éditeurs donc détectent et traitent. Mais il en va de même avec une vidéo lue par vlc. La vidéo contient de l'image au format image (du pixel et de la position) que vlc sait récupérer et afficher à l'écran. Et (pour une vidéo ou un fichier ne contenant que de l'ascii) la distinction se fait par le programme chargé de le traiter ; pas par l'OS.

    Citation Envoyé par sambia39 Voir le message
    Le seul moyen est la lecture des octets magique/signature (exemple [4F 67 67 53] pour ogg ou [25 50 44 46] pdf) du fichier ou la lecture d’un certain nombre d’octets
    C'est vrai qu'il y a les octets magiques. Mais ces octets ne sont pas à destination de l'OS mais des développeurs qui souhaitent pouvoir affiner plus spécifiquement et de façon automatique tel ou tel fichier (lui c'est de l'image, lui du son, lui de la vidéo). Mais ces distinctions ne sont déjà plus du ressort de l'OS ; seulement des humains qui utilisent ces fichiers.

    Citation Envoyé par sambia39 Voir le message
    et donc par défaut le système d’exploitation considère le/les fichier comme étants binaire.
    Non. Il ne les considère pas comme binaires mais comme simples fichiers tout court. Mon premier code (en début de ce post) peut s'appliquer aussi bien à "/etc/passwd" qu'à "/boot/vmlinuz".

    Mieux, on change le code en ceci
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <stdio.h>
     
    int main(int argc, char *argv[]) {
    	FILE *fp;
    	int c;
    	fp=fopen(argv[1], "r");
     
    	while ((c=fgetc(fp)) != EOF)
    		fputc(c, stdout);
    	fclose(fp);
    }
    On compile ensuite ce code dans un exécutable "toto"; on tape ensuite "./toto xxx >yyy" et on aura "yyy" totalement identique au fichier "xxx" demandé ; quel que soit ce fichier et sa nature. Bref ce code est un ersatz (très minimaliste) de la commande "cp". Et nulle part dans ce code on se proccupe de la nature du fichier lu.

    Citation Envoyé par sambia39 Voir le message
    exemple le repertoire /bin/ par exemple, car elle caractérise le format du fichier en question.
    Le répertoire "/bin" est le répertoire dédié aux "binaires" (d'où le nom bin=>binaire). Mais dans ce cas précis, le terme "binaire" ne veut pas dire "fichier binaire comme de l'image ou du son" mais "fichiers exécutables". Et en effet, le dossier "/bin" contient les commandes Unix/Linux (ex cp, ls, vi, more, rm, etc etc etc). Là encore, du point de vue OS pur, ce ne sont que des fichiers. Mais (petite particularité) ces fichiers possèdent un "magic number" spécifique qui fait que le noyau Linux sait les reconnaitre comme pouvant produire un processus => nous (humains) les appelons alors "exécutables". Alors c'est vrai que dans ce cas précis, Linux fait une petite différence. Mais il ne la fait que quand l'humain lui demande "d'exécuter" un programme. Bref il ne fait donc cette différence que quand un humain lui demande de la faire.
    Et ce n'est pas pour que l'OS les reconnaisse qu'on les regroupe, mais pour que les programmeurs (humains) sachent où les trouver. Le répertoire "/bin" ne caractérise pas le format du fichier. C'est le contraire. C'est parce que on ne place dans ce dossier que des exécutables que le dossier /bin ne contient que des exécutables.

    Citation Envoyé par sambia39 Voir le message
    Et sans vouloir faire des vagues ou en fâché plus d’un. GNU/Linux tout comme Unix utilise rarement les extensions de fichiers.
    Aucun OS n'utilise les extensions. ce sont là encore des conventions humaines. Unix ne sait pas que "toto.avi" c'est un film. Mais si je demande file toto.avi alors l'exécutable "file" (programmé par un humain) ira chercher les magic number de "toto.avi" et s'il le reconnait, alors il pourra indiquer "toto.avi est un film". Mais on est déjà sorti de l'OS. Et c'est un système équivalent sous Windows (là, il y a une correspondance entre "extension" et "nature" ; et cette correspondance est stockée dans la base de registre).

    Citation Envoyé par sambia39 Voir le message
    Pour plus de détails, je vous invite a lire Filesystem Hierarchy Standard
    Ce document (je ne le connaissais pas mais je viens de le parcourir) indique l'arborescence type d'un Unix. Il dit que (par exemple) /bin est dévolu aux exécutables, que dans /etc on trouve la configuration, que dans /tmp on trouvera les fichiers de travail, etc etc. Ca ne parle absolument pas d'une quelconque distinction entre "fichiers binaires" et "fichiers texte". Et là aussi le fait que "/etc" ne contienne que des fichiers "human readable" tandis que "/bin" ne contient que des fichiers exécutables est encore une volonté des développeurs. Et là encore l'OS ne fait aucune différence.
    Ce sont des documents dédiés aux développeurs du programme "diff" (qui eux ont besoin parfois de différencier telle ou telle nature de fichier) pour les aider à optimiser ce programme (destiné à afficher les différences entre deux fichiers) selon la nature des fichiers à comparer. Mais là encore on n'est plus dans l'OS, on a basculé dans l'humain.

    En fait, Unix ne connait que 6 types de fichiers
    1. le fichier de type "répertoire". C'est un fichier structuré sur 2 colonnes. L'une contient le nom, l'autre le numéro d'inode. C'est la traduction informatique de ce qu'est un répertoire (un fichier contenant des fichiers). Et grâce à l'association nom/inum, le système Unix sait, quand on demande à accéder à tel fichier, si déjà le fichier est présent (grâce au nom) et ensuite, s'il l'est, où aller le chercher sur disque (grâce à son inode). Et là, si ce fichier est lui-même un dossier, alors rebelote.
    2. le fichier de type "lien symbolique". C'est un fichier qui contient le chemin d'un autre fichier. Là l'OS sait, quand on demande à l'ouvrir, aller chercher le lié correspondant. Et si ce lié est lui-même un lien symbolique alors rebelote.
    3. le fichier spécial de type "bloc" ou "caractère". Ce sont les fichiers associés aux IO (on trouvera par exemple /dev/null (la poubelle), /dev/sda (le premier disque sata), /dev/ptx/N (correspondant à une fenêtre de commande dans ton environnement de bureau (moi j'utilise xfce)) et bien d'autres encore. Même si ce sont deux types distincts on a l'habitude de les mettre ensemble parce qu'ils ont le même but (gérer les IO). Certaines IO se font bloc par bloc (les disques) tandis que d'autres se font caractère par caractère (les écrans) d'où la distinction. Et comme ils sont vraiment différents des autres (ce ne sont pas des fichiers au sens "ils contiennent des datas" mais plutôt des points d'entrée vers le noyau), on les regroupe dans le dossier "/dev" (comme "devices"). Mais là encore /dev n'est pas un dossier pour "typer" les devices, c'est juste un dossier où tous les devices sont regroupés ensembles de par la volonté des développeurs.
    4. le fichier de type "pipe". C'est un fichier permettant de faire communiquer de façon réglementée deux processus
    5. le fichier de type "socket". Analogue au pipe sauf que la communication n'est pas réglementée
    6. et enfin le fichier dit "ordinaire" ; qui va regrouper tous les fichiers de données. Là, pour l'OS, ces fichiers ne contiennent que des octets en vrac. Et dans tout ce fatras, là on verra apparaitre des distinctions mais cette fois humaines (parce que hors OS) pour indiquer "lui c'est une image", "lui c'est une vidéo", "lui ce sont mes comptes bancaires" ou "lui c'est ma liste de commissions pour demain".


    A cette liste bien établie certains rajoutent un 7° type qui est le lien physique (ln toto titi). Personnellement je ne suis pas tout à fait d'accord car créer un lien consiste juste à rajouter un second nom dans un dossier, nom pointant vers le même numéro d'inode que le fichier originel. Or, ce fichier originel est lui-même typé selon les 6 types ci-dessus. Et le type du fichier étant stocké dans son inode (qui reste unique), il s'ensuit que le nouveau fichier est alors du même type que le fichier originel (créer un lien sur un fichier pipe donnera un second fichier pipe). Donc bref pour moi un lien physique n'est pas un 7° type mais plutôt une duplication d'un des 6 types déjà existants).

    Ci-joint un tuto sur les différents types de fichiers Unix.
    Images attachées Images attachées
    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
    Membre expérimenté
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    543
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 543
    Points : 1 745
    Points
    1 745
    Par défaut
    @Bktero:
    1. je n’ai pas écrit que le code était faux, mais qu’il comporte une erreur et je ne parle pas non plus de la boucle en elle-même, je parle du fait qu’il faut effectuer le test d’indicateur d’erreur dans la boucle.

    2. Dans mon premier code oui, je vérifie l’indicateur d’erreur dans la boucle pour savoir s’il n’y a pas eu d’erreurs entre temps sur le flux, car je ne peux absolument pas garantir si ma lecture/mon écriture dans le fichier a réussi où réussiront à la prochaine boucle (tout peut arriver.) et justement ferror() teste s’il n’y a pas eu entre-temps un indicateur d’erreur d'activer après l’exécution de l’instruction précédente si c’est le cas, je ne poursuis pas le déroulement du programme, je sors immédiatement avec un code erreurs. J’ai volontairement injecté un caractère pour simuler une hypothétique erreur quelconque survenue ; certes, ici, c’est une tentative d’écriture, mais le principe d'une erreur est là. Et même-ci à la place, c'était un autre type d’erreur ; avec aucune vérification d'erreur de flux/flot, l'erreur ne sera détectée.
    3. Ici, le sujet n'est pas de déterminer la taille du fichier, il y a déjà un exemple dans la FAQ. Ici, c'est l'exemple de l'empois de feof & ferror() donc, je parle de comment on pourrait utiliser ferror() pour détecter les erreurs de flux.
    4. On y vient :
      4.1-> J’initialise ma variable pointeur a NULL car c’est a mon habitude peut importe ce que les gens diront là dessus; pas besoin/ ou non de l’initialiser voir critiqué. Et n’y a rien de moche à vouloir écrase la valeur que contient ma variable pointeur. Et en quoi, c’est moche ?.

      4.2-> Tu te plantes, si je n’utilise pas le retour d'une fonction; je mets un void cas contraire elle sera utilisée.
      4.3-> Faute de Français là au moins ont est d’accord et je te l’accorde.
      4.5->Une boucle 'pour’ oui et une variable pointeur mise a NULL OK des instructions sur plusieurs lignes oui et alors ??
    5. Si tu as testé sous Windows 10; OK, mais a tu au moins compris que sur le flux (p) il y'a eu une erreur?
      (Juste comme ça ; fputc(‘A’, p); génère bien une erreur). Je vais encore mettre un code dégueulasse sans boucles avec mon fgetc() et peut-être que tu comprendras.

      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
       
      int ret = 0;
      	errno = 0;
      	FILE *p = NULL;
       
      	if( NULL == ( p = fopen("source.c", "r") ) )
      		return EXIT_FAILURE;
       
      	ret = fgetc(p);
      	(void)fprintf(stderr, "%c\n", ret );
      	fputc('A', p );   // indicateur d'erreur activé 
      	ret = fgetc(p);
      	(void)fprintf(stderr, "%c\n", ret );
       
      	//
      	(void)fprintf(stderr,"Errno = %d\n\t:%s\n",
      		errno, strerror(errno) );
       
      	/*
      	* Erreur de le flux 
      	*/
      	if( (ret = ferror(p)) ){
      		(void)fprintf(stderr, "Erreur %d - %d\n",
      			errno, ret );
      		clearerr(p);
      		return EXIT_FAILURE;
      	}
       
      	(void)fprintf(stderr, "Pas d'erreur\n");
      	(void)fclose(p);
      	p = NULL;


    @Sve@r: Arf, j'ai loupé votre message ceci dit, je prends volontiers votre manuel et les remarque sur les fichiers Unix ça pourrais m'être très bénéfique. Merci pour le partage.
    à bientôt.
    Celui qui peut, agit. Celui qui ne peut pas, enseigne.
    Il y a deux sortes de savants: les spécialistes, qui connaissent tout sur rien,
    et les philosophes, qui ne connaissent rien sur tout.
    George Bernard Shaw

  18. #38
    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
    S'il n'est pas faux alors il est correct. Mais s'il est correct, comment peut-il contenir une erreur ? Logique implacable...

    J'ai essayé ce nouveau code que tu proposes et sous Windows 10 avec mingw64, et ça m'affiche ça :
    1
    3
    Errno = 0
    	:No error
    Pas d'erreur
    
    En revanche sous Xubuntu ça fonctionne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    h
    e
    Errno = 9
    	:Bad file descriptor
    Erreur 9 - 1
    Au passage, je suis bien d'accord que c'est une erreur d'écrire sur un flux ouvert en lecture seule.

    J'ai écrit ce 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
    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    int main(void)
    {
        int c = EOF;
        FILE* p = fopen("data.txt", "r");
     
        if(p == NULL)
        {
            fprintf(stderr, "Ouverture impossible %d %s\n", errno, strerror(errno));
            return EXIT_FAILURE;
        }
     
        while(EOF != (c = fgetc(p)))
        {
            /* Afficher le caractere */
            putchar(c);
     
            /* Creer une erreur */
            fputc(c, p);
     
            /* Regarder l'indicateur d'erreur du flux */
            if(ferror(p) != 0)
            {
                fprintf(stderr, "\nErreur detectee %d %s\n", errno, strerror(errno));
                return EXIT_FAILURE;
            }
        }
     
        fclose(p);
        return EXIT_SUCCESS;
    }
    Sous Windows 10 comme sous Xubuntu, il me sort ça :
    1357
    Erreur detectee 9 Bad file descriptor
    Pourquoi mon code fonctionne et pas le tien, mystère pour le moment... Ce que je veux dire c'est qu'on est en train de discuter de détails, visiblement en plus non portable Windows / Linux. Et honnêtement.... ce n'est pas utile.

    Au passage, tu verras que mon code ne caste pas en (void) les retours non utilisés, initialise directement p avec le retour fopen() pour avoir un if() bien plus lisible derrière, et il compile très bien en C89 avec gcc -std=c89 -Wall -Wextra -pedantic main.c. Si tu ne vois pas la différence de lisibilité, alors je pense qu'on va arrêter là notre débat, on ne se mettra jamais d'accord

  19. #39
    Membre expérimenté
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    543
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 543
    Points : 1 745
    Points
    1 745
    Par défaut
    Citation Envoyé par Bktero Voir le message
    S'il n'est pas faux alors il est correct. Mais s'il est correct, comment peut-il contenir une erreur ? Logique implacable...
    ......
    J'ai essayé ce nouveau code que tu proposes et sous Windows 10 avec mingw64, et ça m'affiche ça :
    Au passage, je suis bien d'accord que c'est une erreur d'écrire sur un flux ouvert en lecture seule.
    .......
    Pourquoi mon code fonctionne et pas le tien, mystère pour le moment... Ce que je veux dire c'est qu'on est en train de discuter de détails, visiblement en plus non portable Windows / Linux. Et honnêtement.... ce n'est pas utile.

    Au passage, tu verras que mon code ne caste pas en (void) les retours non utilisés, initialise directement p avec le retour fopen() pour avoir un if() bien plus lisible derrière, et il compile très bien en C89 avec gcc -std=c89 -Wall -Wextra -pedantic main.c. Si tu ne vois pas la différence de lisibilité, alors je pense qu'on va arrêter là notre débat, on ne se mettra jamais d'accord
    Oui, on obtient bien une erreur. Et cette erreur que tu obtiens est dûe au fait que tu as effectué un contrôle sur le flux/flot juste après une lecture/écriture pour t’assurer de détecter d’éventuelles erreurs survenues lors de l’opération précédente (lecture/écriture). Et tu as donc placé ce contrôle au plus prés des opérations effectuées, t’assurant la détection d’erreurs le plus tôt possible. Et depuis le début, j’essaie de te le faire comprendre que je ne parle pas de code faux ou correct, mais d’erreur dûe à la difficulté (et le plus souvent) de trouver ou placer la fonction de contrôle de flux/flots de façon à détecter une éventuelle erreur de traitement.

    Mis à part les deux points sur lesquels on est d’accord à savoir les fautes de français et ferro(), on peut parler du code et de logique implacable ; vu que tu t’es efforcé dès le départ à donner tes explications sur la qualité de mes différents codes sources (rassure-toi, tu auras d’autres occasions d’en débattre) ; mais en attendant, essayons d’élucider le mystère du "Pourquoi mon code fonctionne et pas le tien, mystère pour le moment..." sachant que mes codes ont été faits non pas pour être corrects, mais illustrer le plus possible l'erreur/ le comportement du programme à la détection ou non-détection d’une erreur sur le flux. Donc, je vise le comportement du programme et non la qualité du code et cela s’appelle effectuer une erreur de spécification volentaire.

    Ce qui m’étonne, c’est ta question sur le mystère de savoir pourquoi ça ne marche pas sur Windows 10. Toi qui es très féru de qualité de code et de logique implacable, tu n’as su déterminer à aucun moment qu’il n'y a pas de mystère ; tu aurais dû remarquer certaines choses notamment entre/à partir de la ligne 15 à… .Voici, Quelques orientations, ferror, effectue un test d’erreur de lecture ou d’écriture sur le fichier associé au flux/flot et en cas d’erreur de lecture ou d’écriture sur le Flux/flot, l’indicateur d’erreur pour le flux sera activée et restera active jusqu’à ce que le flux soit fermé ou jusqu’à ce que clearerr() soit appelé. Mais si le flux est NULL, ferro invoque le gestionnaire de paramètres invalide (du moins sous un environnement Windows et probablement Unix). Si l'exécution peut se poursuivre, cette fonction met dans la variable errno, EINVAL et renvoie zéro donc déjà avec ça, tu pourras peut-être comprendre probablement le comportement que pourrait avoir le programme dans un environnement Windows et élucider un mystère de code pourri. Au passage, cela démontre également que tu ne prends pas nécessairement en compte l’environnement dans lequel le programme va évoluer et ne me dis surtout pas que c’est une question de portabilité vu que tu as un exemple type que cela n’est pas lié à la portabilité du code d’autant plus. Je me cite en passant sur ce que j’ai pu écrire concernant mes codes sources.
    Citation Envoyé par sambia39 Voir le message
    ...dans la FAQ comporte une erreur non-détectable dû non pas à un mauvais emploi de la fonction feof()/ferror(), mais plutôt a un mauvais contrôle de flux puisque dans les faits, si l'on a une erreur dans la boucle de traitement exemple une instruction parasite (void)fputc('A',fp); (voir autres) l'erreur ne sera pas détectée, et ce, tout simplement parce que ferror() est en dehors de la boucle. Normalement si elle est placée dans la boucle vous deviez avoir comme du style erreurs (8) bad descriptor.
    ......
    Très souvent, les diverses raisons de la difficulté de l’emplois des fonctions feof()/ferror() sont dues à comment doit-on placer les fonctions pour contrôler, sortir/détecter les erreurs de flux dans la boucle, c'est-à-dire la façon/le moyen le plus évident d'utiliser feof()/ferror() pour contrôler une boucle/detecter des erreurs voir les deux. S'il faut réécrire dans un premier temps l'ensemble de ce que j'avance cela s'apparenterais au code source-ci dessous, mais attention, c'est un exemple il peut donc y avoir des erreurs surtout qu'il y a une autre façon d'écrire les instructions.
    ......
    Je vais encore mettre un code dégueulasse sans boucles avec mon fgetc() et peut-être que tu comprendras.

    Parlons maintenant de ton code source. J’ai tout de même testé à mon tour ton programme sur Windows 10 avec un compilateur bien de chez Microsoft sans option, sous une machine virtuelle et j’obtiens bien comme résultat le message d’erreur, chose qui est bien. En revanche, ce qui m’intéresse est ta logique implacable. Commençons par le message d’erreur et quelques éléments qui sont absents dans ton code, mais disons que ce n’est pas bien grave.
    Dans ton exemple, on obtient bien une erreur "mauvais descripteur de fichier", cela est effectivement dû à une opération non permise sur un descripteur de fichier ouvert en lecture seule. Donc il faut s’assurer de signifier que l’opération est dûe à une opération non permise, car on a manipulé un descripteur de fichier en lecture seule. Et quand on quitte/gère le comportement de son programme lors d’une erreur avant de quitter, on ne laisse pas le programme hôte gérer l’échec d’un programme. Il faut prendre les mesures appropriées en amont avant de pouvoir quitter proprement et signifier au système hôte que le programme a quitté en raison d’une erreur (sans rentrer dans un débat de descripteur de fichier sous un environnement Windows/Unix). Donc un clearerr ne fera pas de mal.

    Pour encore ne pas être d’accord avec toi, voici un programme dégueulasse dans lequel j’emploie volontairement une boucle "pour" avec une variable existante uniquement le temps de la boucle et beaucoup moins lisible. J’aimerais savoir ce que tu en penses .
    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
    36
    37
     
    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    int main( void ){
     
    	FILE *p = NULL;
    	if( NULL == (p = fopen("source.c", "r")) ){
    		(void)fprintf(stderr, "(%d)Erreur\t:%s\n",
    			errno, strerror(errno) );
    		return EXIT_FAILURE;
    	}
     
    	for( int r = 0; !feof(p); r = ferror(p) ){	
    		if( r ){
    			(void)fprintf(stderr, 
    				"\nErreur dûe à :%s\nCause :%s\n",
    				strerror(r), strerror(errno) );
    			clearerr(p);
    			return EXIT_FAILURE;
    		}
    		(void)fputc( fgetc(p), stderr );
    		(void)fputc('c', p );
    	}
     
    	if( EOF == fclose(p) ){
    		(void)fprintf(stderr, 
    			"Erreur: %d %s\n", 
    			errno, strerror(errno));
    		return EXIT_FAILURE;
    	}
     
    	p = NULL;
    	return EXIT_FAILURE;
    }

    À bientôt.
    Celui qui peut, agit. Celui qui ne peut pas, enseigne.
    Il y a deux sortes de savants: les spécialistes, qui connaissent tout sur rien,
    et les philosophes, qui ne connaissent rien sur tout.
    George Bernard Shaw

  20. #40
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    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 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par sambia39 Voir le message
    Pour encore ne pas être d’accord avec toi, voici un programme dégueulasse dans lequel j’emploie volontairement une boucle "pour" avec une variable existante uniquement le temps de la boucle et beaucoup moins lisible. J’aimerais savoir ce que tu en penses .
    Euh... déjà moi je n'en pense pas tellement du bien. Mais pas tellement pour le "r" dans la boucle (ça c'est autorisé depuis C99 et je trouve ça pas plus mal) mais pour tout le reste.
    Tout d'abord, tu utilises feof() pour tester la fin de lecture (lecture dans le cas où tout se passe bien je veux dire) alors qu'il est dit depuis le début que cette fonction ne sert pas à ça. Total, si tu supprimes la ligne (void)fputc('c', p ) qui provoque une erreur de flux, alors le code s'exécute et lit tout le fichier mais il affiche à la fin un caractère de plus que ce que contient réellement le fichier lu.
    Ensuite ben en cas d'erreur tu quittes sans avoir fermé le fichier. De plus tu remets à zéro les flags du fichier alors que tu quittes la fonction. De même à la fin du code tu mets p à NULL alors que tu ne le traites plus (ne jamais remplir une variable sans la traiter ensuite). Et enfin tu écris le caractère lu sur le flux stderr (c'est un flux dédié aux messages d'erreur, pas aux messages normaux du code).

    Et tous ces casts à la c.. !!! Tu penses vraiment être propre en écrivant ainsi ? Tu ne sais pas que le trop est l'ennemi du bien ?? Tu ne connais pas le cast implicite ??? Surtout que le cast a un but quand-même: celui de pouvoir faire traiter le truc casté dans un traitement qui le verra différemment de ce qu'il est. Ex int i; for (i=1; i < 10; i++) printf("%f\n", (i+1)/float(i)). Si là je ne caste pas le "i" en float, alors ma division ne se fera pas comme je le souhaite (et accessoirement j'ai mis du temps à trouver cet exemple qui n'est même pas à 100% démonstratif car on peut faire autrement => printf("%f\n", (i+1.0)/i) ce qui prouve que dans la 98% des cas, le cast peut s'éviter).
    Ici quel est le but de tes casts ? Juste dire "je ne prendrai pas en compte le retour de printf()". Hé ben ne le prends pas en compte quoi. Tout simplement. C'est complètement idiot d'écrire "je ne ferai pas telle opération". Suffit de simplement ne pas la faire. C'est comme les gens qui disent "je voudrais dire..." ben ils n'ont qu'à le dire, c'est beaucoup plus simple !!!

    Et (dernier détail) tes inversions d'égalité (écrire if( NULL == (p = fopen("source.c", "r")) au lieu de if ((p=fopen("source.c", "r")) == NULL)) et qui me font marquer un (mini) temps d'arrêt quand je lis ce type d'instruction pour la remettre dans le sens de lecture naturel. Alors ok ça protège de celui qui oublierait l'opérateur de comparaison du C (et qui écrirait if ((p=fopen("source.c", "r")) = NULL) mais bon, t'es-t-il déjà arrivé d'écrire "=" en pensant "==" ? Si ça t'es arrivé, combien de temps t'as mis pour touver l'erreur et la corriger ?

    En C (et probablement dans d'autres langages), il y a l'écriture scolaire, rigoriste, et qui produit un truc qui pique les yeux ; et il y a ensuite l'écriture intuitive, naturelle, peut-être moins académique mais tellement plus en adéquation avec notre logique naturelle...
    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]

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 3 PremièrePremière 123 DernièreDernière

Discussions similaires

  1. Réponses: 1
    Dernier message: 11/07/2006, 22h47
  2. Erreur de sgmentation avec malloc
    Par simonm dans le forum C
    Réponses: 5
    Dernier message: 27/02/2003, 08h29
  3. Réponses: 4
    Dernier message: 03/12/2002, 16h47
  4. delphi XML / HTML caractéres speciaux !
    Par adem dans le forum EDI
    Réponses: 2
    Dernier message: 29/08/2002, 17h48

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