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 :

Vérification de la taille allouée et bonnes pratiques


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    10
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2006
    Messages : 10
    Par défaut Vérification de la taille allouée et bonnes pratiques
    Bonjour,

    Dans l'exemple ci-dessous, je cherche à remplir un tableau à partir des données binaires lues dans un fichier (binaire).

    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
    #define C_NB_MAX_ELEM 10
    #define NOMFICHIERSOURCE "Exemple.bin"
     
    #include <stdlib.h>
    #include <string.h>
     
    //Pour l'exemple
    typedef int32_t Element_t;
     
    //Exemple de programme remplissant des tableaux
    in32_t main( void )
    {
    	Element_t TableauExemple[C_NB_MAX_ELEM]:
    	size_t NbElemLus = 0;
     
    	NbElementLus = importBinaireElement( NOMFICHIER, TableauExemple );
     
    	return EXIT_SUCCESS
    }
     
    size_t importBinaireElement( char_t * p_NomFichier, Element_t * p_TableauARemplir )
    {
    	FILE * p_fichierBinaire = NULL; //Tant que le fichier n'est pas ouvert, on met une adresse invalide
    	size_t NombreElemLus = 0;
     
    	//Verifier que l'epace memoire est disponible
    	if( p_TableauARemplir != NULL )
    	{
    		/* 
    			Cette fonction remplit la table p_TableauARemplir de 0. Cette table comporte C_NB_MAX_ELEM elements de taille "sizeof(Element_t)" octets.
    		*/
     
    		//Ouverture du fichier binaire
    		/*
    			Le fichier est ouvert en lecture ('r') et en mode binaire ('b').
    		*/
    		p_fichierBinaire = fopen(p_NomFichier, "rb");
     
    		//Si l'ouverture du fichier a reussi, la variable p_fichierBinaire contient une valeur valide
    	   if (p_fichierBinaire != NULL)
    	   {
    			/*
    				Cette fonction lit au plus C_NB_MAX_ELEM elements, chacun de taille "sizeof(Element_t)" octets, depuis le fichier accede au travers de p_fichierBinaire.
    				Les elements sont ranges dans p_TableauARemplir. La fonction retourne le nombre d'elements vraiments lus.
    			*/
    			NombreElemLus = fread(p_TableauARemplir, sizeof(Element_t), C_NB_MAX_ELEM, p_fichierBinaire);
     
    			// La lecture etant terminee, on ferme le fichier et affectons a nouveau une valeur invalide a  p_fichierBinaire
    			fclose(p_fichierBinaire);
    			p_fichierBinaire = NULL;
    	   }
    	}
     
    	//Retourner le nombre d'elements importes
    	return NombreElemLus;
    }
    Ce programme doit être statique. Je définis donc une taille maximum pour le tableau que je souhaite remplir : elle est égale au nombre maximum d'éléments que pourrait contenir le tableau.

    La ligne suivante a pour but de controler que le tableau où seront rangées au plus C_NB_MAX_ELEM données est suffisamment alloué en mémoire.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if( p_TableauARemplir != NULL )
    Malheureusement, je ne sais pas comment vérifier la quantité de mémoire allouée à partir d'une adresse. Ici, je voudrais vérifier que p_TableauARemplir est l'adresse du premier byte d'une zone mémoire à laquelle qu'au moins C_NB_MAX_ELEM*sizeof(Element_t) bytes auront été alloués. Est-ce possible. Pourriez-vous m'aider ?

    Dans cet exemple, ce n'est peut-être pas necessaire, mais la fonction importBinaireElement pourrait être utilisée dans des circonstances moins favorables.

    Merci d'avance.

  2. #2
    Invité(e)
    Invité(e)
    Par défaut
    Bonjour,

    Tu peux modifier le prototype de importBinaireElement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    size_t importBinaireElement( char_t * p_NomFichier, 
        Element_t * p_TableauARemplir, size_t taille_tableau );
    Et l'appeler comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    size_t nb_elem_max = sizeof TableauExemple  / sizeof *TableauExemple ;
    NbElementLus = importBinaireElement( NOMFICHIER, TableauExemple, nb_elem_max );
    Et la fonction de lecture devient :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    NombreElemLus = fread(p_TableauARemplir, sizeof(Element_t), taille_tableau, 
        p_fichierBinaire);

  3. #3
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Par défaut
    Citation Envoyé par roh01 Voir le message
    Ici, je voudrais vérifier que p_TableauARemplir est l'adresse du premier byte d'une zone mémoire à laquelle qu'au moins C_NB_MAX_ELEM*sizeof(Element_t) bytes auront été alloués. Est-ce possible. Pourriez-vous m'aider ?
    Directement, c'est strictement impossible à partir d'un simple pointeur : en fait, tu ne peux même pas savoir (s'il est différent de NULL) si cela pointe vers de la mémoire allouée, globale ou même simplement accessible !
    Si c'est un pointeur initialisé n'importe comment, donc vraisemblablement dans une zone mémoire non mappée, tu n'as pas d'autre choix que de tenter de déréférencer le pointeur pour "tester" la zone... Si ça plante, c'est que c'était mauvais, et si ça marche, ça ne veut même pas dire que c'est de la mémoire réellement "libre". Comble de joie, tu ne peux même pas intercepter l'erreur (SIGSEGV usuellement)...
    Bref, le flou, il faut faire confiance à l'appelant (principe majeur en C, d'ailleurs).

    C'est éventuellement possible avec des classes C++, mais en C, tu n'as aucune solution à part celle indiquée par mabu : passer la taille du tableau en paramètre, en plus du tableau lui-même, et faire confiance à l'utilisateur de ta fonction...


    Note : Si tu veux blinder au maximum, et que tu es sous Visual Studio, pense aussi à tester la valeur 0xCCCCCCCC en mode Debug, cela permet de vérifier les pointeurs non-initialisés qui sont par défaut à cette valeur sous VS (en Release, ils n'ont aucune valeur particulière s'ils ne sont pas initialisés).
    Tu obtiens un truc du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    if ((p_fichierBinaire != NULL)
        #ifdef _DEBUG
        && (p_fichierBinaire != 0xCCCCCCCCul)
        #endif
        ) {
            ....
        }
    Cela ne coûte pas grand-chose, et c'est une bonne pratique générale...
    Pour ma part, j'utilise un truc hérité de Delphi que j'apprécie particulièrement, c'est une macro "assigned" qui teste directement la validité d'un pointeur, fonction qui est alors adaptable à pas mal de plate-formes (y compris celles ayant un mapping mémoire réduit) par compilation conditionnelle :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #define assigned(pointer) ( \
        ((pointer)!=NULL) \
        #if defined(_DEBUG) && defined(_MSC_VER)
        && ((pointer)!=(0xCCCCCCCCul)) \
        #endif
        )
     
    /* Usage :*/
        if (assigned(mon_pointeur)) {
            ....
        }
    A utiliser bien sûr avec les précautions d'usage liées aux répétitions des paramètres de macros...
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  4. #4
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    10
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2006
    Messages : 10
    Par défaut
    Merci pour vos réponses.

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

Discussions similaires

  1. Bonnes pratiques de protections individuelles
    Par Community Management dans le forum Sécurité
    Réponses: 23
    Dernier message: 11/06/2024, 11h23
  2. Taille des boites mail et bonne pratiques
    Par SebRo dans le forum Exchange Server
    Réponses: 3
    Dernier message: 11/05/2012, 21h46
  3. [Bonne pratique]Stratégie d'allocation
    Par jowo dans le forum C
    Réponses: 1
    Dernier message: 05/10/2005, 14h47
  4. [FOREIGN K] Valeur de champ = nom de table. Bonne pratique ?
    Par Seb des Monts dans le forum Langage SQL
    Réponses: 9
    Dernier message: 17/05/2005, 10h56

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