+ Répondre à la discussion Actualité déjà publiée
  1. #1
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Inscrit en
    décembre 2003
    Messages
    14 508
    Détails du profil
    Informations personnelles :
    Âge : 61
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : décembre 2003
    Messages : 14 508
    Points : 20 246
    Points
    20 246

    Par défaut Les types abstraits de données (ADT)

    Les types abstraits de données (ADT)

    Cet article présente la possibilité de programmer en C en utilisant une approche plus 'objet' que 'fonction'.
    Lien : http://emmanuel-delahaye.developpez.com/tutoriels/c/types-abstraits-donnees-c/ (cliquez ici)

    N'hésitez pas à donner vos avis et à apporter des commentaires sur cet article à la suite de ce message

    Vous pouvez également noter cet article en utilisant l'outil de notation de cette discussion dans la barre de menu en haut à droite


    Pas de Wi-Fi à la maison : CPL

  2. #2
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur systèmes embarqués
    Inscrit en
    juin 2009
    Messages
    3 582
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur systèmes embarqués

    Informations forums :
    Inscription : juin 2009
    Messages : 3 582
    Points : 9 406
    Points
    9 406
    Billets dans le blog
    1

    Par défaut

    Bonjour,

    Emmanuel ne me répondra sûrement pas (sauf si un mail de notification lui fait lâcher son luth ), mais d'autres pourront m'éclairer sur le sujet.

    Ma question concerne l’initialisation dans le constructeur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    struct objet * objet_create (void)
    {
       struct objet * self = malloc (sizeof *self);
     
       if (self != NULL)
       {
          /* initialisation a 0 */
          static const struct objet z = {0};
          *self = z;
       }
     
       return self;
    }
    Je m'interroge sur l'intérêt d'utiliser une copie, a fortiori d'une variable static.

    Question 1 : pourquoi ne pas simplement faire self->data = 0; ? On pourra me dire que si la structure est longue, c'est plus long à écrire mais ce sera aussi plus clair qu'une liste initialisation (notamment si on ne souhaite pas mettre que des zéros. La partie V-C-3. Remarque laisse penser que cette technique z = {0} est surtout adaptée pour tout mettre à zéro de manière compacte).

    Question 2 : pourquoi déclarer z comme étant static ? Y a t-il un gain en performance ou en utilisation mémoire par rapport à la création d'une variable locale à chaque appel ?

    Question 3 : le const relève purement de la bonne pratique ou a t-il aussi un intérêt pour une potentielle optimisation ?

    Merci d'avance pour vos réponses

  3. #3
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : juin 2005
    Messages : 5 761
    Points : 14 081
    Points
    14 081

    Par défaut

    1 - Définir un objet z pour l'initialisation permet de l'utiliser avec une simple assignation entre structures ce qui est certainement plus efficace que l'initialisation champ par champ. C'est pratiquement aussi clair à la lecture à mon avis, en centralisant les valeurs, à condition que la structure ne soit pas trop grosse. Mais même dans ce cas, on peut nommer les initialiseurs (en C99) ce qui rend toute la clarté à l'écriture.

    2- Le fait de le déclarer static permet qu'il soit créé et initialisé une et une seule fois avant même le début de l'exécution du programme au lieu d'être créé, initialisé et détruit à chaque appel et d'encombrer la pile.

    3- Le fait de le déclarer const permet probablement au compilateur de le créer dans la section code plutôt que dans la section des globales si il le préfère.
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  4. #4
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    juin 2007
    Messages
    5 029
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : juin 2007
    Messages : 5 029
    Points : 16 841
    Points
    16 841

    Par défaut

    Je suis peut-être à coté de la plaque, mais en quoi est-ce plus efficace que ceci?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    struct objet * objet_create (void) {
       return calloc (1, sizeof *self);
    }
    Il me semble que justement calloc zérote toute la zone mémoire allouée
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  5. #5
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur systèmes embarqués
    Inscrit en
    juin 2009
    Messages
    3 582
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur systèmes embarqués

    Informations forums :
    Inscription : juin 2009
    Messages : 3 582
    Points : 9 406
    Points
    9 406
    Billets dans le blog
    1

    Par défaut

    @leternel : si tu veux tout mettre à zéro, c'est peut-être mieux. Mais tu perds la finesse de valeurs autres que zéro, tu dois être moins générique...

    @diogene : je n'avais effectivement pas pensé aux designated initializers pour augmenter la lisibilité si le nombre de champs augmente. C'est une bonne idée !

    Pour regarder un peu plus en détails la différence entre la copie d'une structure et l'affectation champ par champ, j'ai fait un petit code et je regarde le résultat de la compilation de MinGW (avec l'option -O3) avec l'utilitaire objdump.exe.

    Voici le 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
    #include <stdio.h>
    #include <stdlib.h>
     
    struct objet
    {
       int data;
       int again;
       float and;
    };
     
    struct objet *self;
     
    void field(void)
    {
        self->data = 0;
        self->again = 0;
        self->and = 0.0;
    }
     
    void copy_static(void)
    {
        struct objet z = {0};
        *self = z;
    }
     
    int main(void)
    {
        self = malloc(sizeof *self);
     
        field();
        copy_static();
     
        return 0;
    }
    Et voici le résultat d'objdump :
    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
     
    main.o:     file format pe-i386
     
     
    Disassembly of section .text:
     
    00000000 <_field>:
       0:	55                   	push   %ebp
       1:	89 e5                	mov    %esp,%ebp
       3:	a1 00 00 00 00       	mov    0x0,%eax
       8:	c7 00 00 00 00 00    	movl   $0x0,(%eax)
       e:	a1 00 00 00 00       	mov    0x0,%eax
      13:	c7 40 04 00 00 00 00 	movl   $0x0,0x4(%eax)
      1a:	8b 15 00 00 00 00    	mov    0x0,%edx
      20:	a1 00 00 00 00       	mov    0x0,%eax
      25:	89 42 08             	mov    %eax,0x8(%edx)
      28:	5d                   	pop    %ebp
      29:	c3                   	ret    
     
    0000002a <_copy_static>:
      2a:	55                   	push   %ebp
      2b:	89 e5                	mov    %esp,%ebp
      2d:	57                   	push   %edi
      2e:	56                   	push   %esi
      2f:	53                   	push   %ebx
      30:	83 ec 10             	sub    $0x10,%esp
      33:	8d 5d e8             	lea    -0x18(%ebp),%ebx
      36:	b0 00                	mov    $0x0,%al
      38:	ba 0c 00 00 00       	mov    $0xc,%edx
      3d:	89 df                	mov    %ebx,%edi
      3f:	89 d1                	mov    %edx,%ecx
      41:	f3 aa                	rep stos %al,%es:(%edi)
      43:	a1 00 00 00 00       	mov    0x0,%eax
      48:	89 c2                	mov    %eax,%edx
      4a:	8d 5d e8             	lea    -0x18(%ebp),%ebx
      4d:	b8 03 00 00 00       	mov    $0x3,%eax
      52:	89 d7                	mov    %edx,%edi
      54:	89 de                	mov    %ebx,%esi
      56:	89 c1                	mov    %eax,%ecx
      58:	f3 a5                	rep movsl %ds:(%esi),%es:(%edi)
      5a:	83 c4 10             	add    $0x10,%esp
      5d:	5b                   	pop    %ebx
      5e:	5e                   	pop    %esi
      5f:	5f                   	pop    %edi
      60:	5d                   	pop    %ebp
      61:	c3                   	ret    
     
    00000062 <_main>:
      62:	55                   	push   %ebp
      63:	89 e5                	mov    %esp,%ebp
      65:	83 e4 f0             	and    $0xfffffff0,%esp
      68:	83 ec 10             	sub    $0x10,%esp
      6b:	e8 00 00 00 00       	call   70 <_main+0xe>
      70:	c7 04 24 0c 00 00 00 	movl   $0xc,(%esp)
      77:	e8 00 00 00 00       	call   7c <_main+0x1a>
      7c:	a3 00 00 00 00       	mov    %eax,0x0
      81:	e8 7a ff ff ff       	call   0 <_field>
      86:	e8 9f ff ff ff       	call   2a <_copy_static>
      8b:	b8 00 00 00 00       	mov    $0x0,%eax
      90:	c9                   	leave  
      91:	c3                   	ret    
      92:	90                   	nop
      93:	90                   	nop
    J'ai ensuite rajouté le mot-clé static --> static struct objet z = {0};. On obtient cette fois pour la fonction modifiée (le reste ne change pas, normal) :
    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
    0000002a <_copy_static>:
      2a:	55                   	push   %ebp
      2b:	89 e5                	mov    %esp,%ebp
      2d:	57                   	push   %edi
      2e:	56                   	push   %esi
      2f:	53                   	push   %ebx
      30:	a1 00 00 00 00       	mov    0x0,%eax
      35:	89 c2                	mov    %eax,%edx
      37:	bb 00 00 00 00       	mov    $0x0,%ebx
      3c:	b8 03 00 00 00       	mov    $0x3,%eax
      41:	89 d7                	mov    %edx,%edi
      43:	89 de                	mov    %ebx,%esi
      45:	89 c1                	mov    %eax,%ecx
      47:	f3 a5                	rep movsl %ds:(%esi),%es:(%edi)
      49:	5b                   	pop    %ebx
      4a:	5e                   	pop    %esi
      4b:	5f                   	pop    %edi
      4c:	5d                   	pop    %ebp
      4d:	c3                   	ret
    Enfin, avec le mot-clé const :
    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
    0000002a <_copy_static>:
      2a:	55                   	push   %ebp
      2b:	89 e5                	mov    %esp,%ebp
      2d:	57                   	push   %edi
      2e:	53                   	push   %ebx
      2f:	a1 00 00 00 00       	mov    0x0,%eax
      34:	89 c3                	mov    %eax,%ebx
      36:	b0 00                	mov    $0x0,%al
      38:	ba 0c 00 00 00       	mov    $0xc,%edx
      3d:	89 df                	mov    %ebx,%edi
      3f:	89 d1                	mov    %edx,%ecx
      41:	f3 aa                	rep stos %al,%es:(%edi)
      43:	5b                   	pop    %ebx
      44:	5f                   	pop    %edi
      45:	5d                   	pop    %ebp
      46:	c3                   	ret
    On voit donc bien que static const produit une bien meilleure copie de structure la première copie naive.

    Sauf qu'en l'état actuel, je n'ai pas l'impression que la méthode par copie de structure soit plus performante que l'affection champ par champ. Mais je ne suis pas assez connaisseur en assembleur pour tirer une conclusion sérieuse...

  6. #6
    Membre expert

    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    octobre 2011
    Messages
    887
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : octobre 2011
    Messages : 887
    Points : 3 289
    Points
    3 289

    Par défaut

    Bonjour,

    static const struct objet z; et static const struct objet z={0}; ont normalement exactement le même effet puisque toute variable statique est initialisée avec des 0, enfin plus précisément avec des valeurs nulles apropriées (0, NULL, 0.0, etc ...). Le préciser sert uniquement à la lecture et à la compréhension, puisque de toute façon il n'y aura pas de code généré pour ça. Si les valeurs par défaut doivent être différentes alors il devient utile de les préciser (ce qui ne produira toujours pas de code pour z), mais à titre personnel j'utiliserais dans la mesure du possible une fonction pour cela (quitte à utiliser la même technique).
    Un avantage est lors de la maintenance du code (parfois), on rajoute des champs, on en enlève mais l'initialisation reste (normalement) correcte, même si cela peut s'avérer dangeureux.

    La différence entre un calloc et cette méthode :
    • calloc met tous les bits à 0. L'initialisation met des valeurs nulles. Personnellement je n'ai jamais rencontré de plateformes où NULL ne «vaut» pas 0, ou où le réel 0 ne peut pas être encodé uniquement avec des bits 0.
    • l'initialisation pourrait contenir des valeurs non nulles, ce qui fait «du travail en double» si on modifie ensuite les champs.


    Utiliser const est certainement une bonne pratique si elle est utilisée à bon escient. Tout comme utiliser restrict, _Noreturn ou même inline d'ailleurs. Toute indication utile permet au compilateur de produire du code meilleur/plus performant/...
    gcc implémente plusieurs attributs qui sont très utiles pour lui indiquer qu'une fonction renvoie un pointeur nouvellement alloué, qu'une fonction est pure, etc. Cela te lie au compilo, même si clang ou icc permettent aux aussi de le faire.

Discussions similaires

  1. Classe : type abstrait de donnée
    Par problems99 dans le forum Langage
    Réponses: 6
    Dernier message: 11/01/2011, 14h59
  2. Réponses: 26
    Dernier message: 10/01/2008, 23h37
  3. Type abstrait de donnée
    Par mia123 dans le forum Pascal
    Réponses: 1
    Dernier message: 01/06/2007, 15h00
  4. [VB] Les types de données en VB
    Par jam92400 dans le forum VB 6 et antérieur
    Réponses: 9
    Dernier message: 16/05/2006, 22h37

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