Bonjour à tous,
Peut on eclairer ma lenterne sur les unions s'il vous plait ?!
J'ai fait le tour des cours sur le site mais je suis un peu dans le flou.
Version imprimable
Bonjour à tous,
Peut on eclairer ma lenterne sur les unions s'il vous plait ?!
J'ai fait le tour des cours sur le site mais je suis un peu dans le flou.
T'es sûr d'avoir bien cherché ?
Structures, unions et énumérations.
Oui c'est le cours que j'avais vu.Citation:
Envoyé par jbarreau-mainson
Mais je ne vois pas trop à quoi cela sert ou plutot comment s'en servir...
Tu ne sais pas t'en servir ou tu ne vois pas leurs utilités ? Dans le premier cas je ne vois pas ce que je pourrai faire pour toi car il y a déjà des exemples dans le cours il me semble. Dans le deuxième cas, tu n'as juste pas encore assez d'expérience pour te rendre compte de leur utilité. Ne brusque pas les choses, ça viendra avec le temps. Ou bien j'ai encore mal compris la question ?
Eh bien en fait je ne voit pas la difference avec une structure, mis à part le fait que les champs d'une union partagent le même espace mémoire.
J'ai en fait un long qui a une valeur forcée, j'affiche la valeur de ce long à travers ce code :
Et j'aimerais à partir de là pouvoir déterminer msw, lsw, lsb et msb.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 typedef unsigned char uchar; int main() { long lg; lg = 0x12345678; uchar *pc; write(1,"lg = ", 5); for(pc = (uchar *)(&lg);pc < (uchar *)(&lg + 1); pc++) { printf("%.2X ", 0xFF&(*pc)); } }
On m'impose d'utiliser struct et union mais je bloque un peu ...
Je pensais me diriger vers 3 struct :
1 long lng; // Mot entier
2 short shrt; // MSW & LSW
1 char tab[3]; // Tab de 4 éléments : (lsb et msb)*2
Je ne sais pas si c'est très clair :?
Bin volià la différence ! Dans une structure, les champs ne se chevauchent pas. Dans une union, on ne peut "activer" qu'un champ à chaque utilisation de l'union.Citation:
Eh bien en fait je ne voit pas la difference avec une structure, mis à part le fait que les champs d'une union partagent le même espace mémoire.
Pour ce qu'on te demande de faire, c'est ta méthode qui est la bonne car portable (mais dans tous les cas on ne peut savoir si le premier octet est le msb ou le lsb qu'en sachant la plateforme sur laquelle on est. sur un processeur x86, premier octet en mémoire = lsb). Tu peux faire une version non portable en utilisant les unions avec la méthode que je vais te montrer un peu plus bas. L'idée c'est d'aller faire quelque chose comme ceci :
L'utilisation d'une union permet de ne pas avoir à faire un memcpy.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 typedef struct bbbb_s { unsigned char b0; unsigned char b1; unsigned char b2; unsigned char b3; } BBBB; ... long lg = 0x12345678; BBBB b; // Sachant qu'un long fait 4 octets et un BBBB tout de même, // on peut copier tous les bits de lg vers b et lire facilement // le msb, le lsb, etc. memcpy(&b, &lg, 4); printf("lsb = %.2x\n", b.b0); printf("msb = %.2x\n", b.b3);
Code:
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> typedef struct bbbb_s { unsigned char b0; unsigned char b1; unsigned char b2; unsigned char b3; } BBBB; typedef struct ww_s { unsigned short w0; unsigned short w1; } WW; union lng { long lg; BBBB b; WW w; }; int main() { union lng u; u.lg = 0x12345678; printf("lsb = %.2x\n", u.b.b0); printf("msb = %.2x\n", u.b.b3); printf("lsw = %.2x\n", u.w.w0); printf("msw = %.2x\n", u.w.w1); return 0; }
Pour la réponse à ton problème, voir plus haut.
Pour l'utilité, en voici un mini-exemple..
Soit une donnée que tu manipules, qui peut prendre n'importe quelle valeur int, long, float, double, char.
Si tu veux faire un "objet" ayant cette valeur, et le manipuler de manière "transparente", tu as 2 choix..
Structure :
Union :Code:
1
2
3
4
5
6
7
8
9 typedef struct _pValue { int i ; long l ; float f ; double d ; char c ; } Value ;
Code:
1
2
3
4
5
6
7
8
9 typedef union _pValue { int i ; long l ; float f ; double d ; char c ; } Value ;
Dans le premier cas, la taille sera la somme des tailles (au moins), dans le second la plus grande (sizeof(double) ).
Si donc tu n'as pas besoin d'optimisation, ou que ta "modélisation" est peu importante, la structure marche bien.
Si par contre tu as (auras) beaucoup d'objets en mémoire, et/ou que ta "modélisation" (objet) est importante, tu prendras l'union, qui demande beaucoup moins de mémoire et qui est plus "object-like"...
:D
C'est beaucoup plus clair maintenant, merci à vous !
@souviron34 : Je ne comprend pas en quoi ton exemple serai utile ...
Car certe l'union gagne de la place , mais du coup la multitude de types que t'utilise son la même chose, donc si tu en modifie tu les modifie tous. Donc si tu as besoin de plus de variables aux même instants , tu aura besoin de refaire des variables de ton union. Ou alors c'est dans un cas ( que je trouve dangereux ) ou tu réutilise la meme variable après utilisation... donc avec un autre type comme te le permet l'union ...
( Je trouve ça dangereux, car cela peut être source de bug , si on est pas rigoureux )
Il faut certes être prudent, mais l'usage d'une union pour gagner de la place et donc de "recycler" une ancienne variable en en changeant le type est une pratique assez fréquente (bien qu'en perte de vitesse car de moins en moins nécessaire avec l'augmentation de la mémoire disponible même dans les environnement limité) et c'est à peu près le seul cas où l'utilisation de l'union est portable.
Voir plus bas, mais ton "premier cas" est impossible : tu ne fais une union que de choses logiques qui ne bougent pas dans le temps (voir exemple ci-dessous).
Dans ton "second cas", c'est pareil. Ce cas est rare, mais l'utilisation la plus fréquente est ci-dessous...
C'est au contraire très courant dans les softs industriels,pour une raison simple :
comme dit plus haut, cela correspond à une programmation "orientée objet".
Si tu as par exemple un serveur envoyant des données (je l'ai eu pour la météo par exemple). Ces données sont par exemple la température (nombre réel : degrés), la précipitation (nombre entier : mm), le nom de la station de mesure (chaine de caractères), la photo de ce qui se passe à l'extérieur de la station (buffer de unsigned char : image), etc etc... tu as une routine Receive_Data. Cette fonction va décoder la réponse et stocker dans des buffers les données, qui sont de types différents. Sauf qu'après, dans tout le soft, la valeur de la donnée n'est qu'un des multiples éléments de la donnée (date d'émission, date de réception, posiition géographique, etc etc).
Donc tu fais une union, car ce n'est pas le même endroit "recyclé", comme dit plus haut, mais différentes manières d'accéder à la valeur pour des types différents...
Admettons que tu aies 450 000 points. Au lieu d'avoir 450 000 fois (4+4+8+8+1) octets tu auras 450 000 * 8, soit un gain absolument non négligeable en mémoire (66% de gain), et de plus beaucoup plus transparent :
Tu auras par exemple des fonctions style Affiche_Data, Trace_Data, etc etc, et ce ne sera qu'au niveau le plus profond que tu décideras en fonction du type qu'est-ce que tu choisis.
@gl :
- primo il faut toujours tenter de faire un programme qui consomme le moins possible : tu ne peux pas imposer à un client (même si c'est ce que fait M$) d'augmenter indéféniment sa mémoire), et d'autre part tu ne peux pas forcément savoir de combien tu disposeras (mes programmes tournent sans rien changer de 2 Megs à 500 Gigs de mémoire).
- secondo le problème n'est pas de recycler mais de programmer de manière "objet" et cohérente... Je ne comprend donc pas ce que tu dis que c'est de moins en moins utilisé... C'est au contraire dans le droit-fil de la POO. C'est beaucoup plus compliqué de faire rentrer un schéma de structure dans un schéma OO que de dire que la valeur est soit un entier, soit un réel, soit .., car cela devient une "contrainte d'implémentation" ou de langage, et non une modélisation.
Oui et ? Où est-ce que j'ai prétendu le contraire ?
Je répondais à la remarque de LittleWhite concernant la réutilisation de mémoire grâce à une union, qui est bel et bien une pratique en voie de disparation (et je serais tenter de dire heureusement).
Je ne prétends pas que les autres utilisations de l'union était de moins en moins utilisé. Si mon message précédent est ambigu, je m'en excuse.
Ceci étant l'utilisation des union pour programmer "orienté objet" n'est qu'une des façons de faire et ce n'est pas celle que j'ai rencontrée ou utilisée le plus fréquemment (généralement c'est plutôt à base de void* + taille du type). Mais il est fort possible que dans d'autres domaines que le mien, l'utilisation d'union dans le but de faire de la POO soit plus fréquent.
Par contre je n'ai pas compris dans ton exemple où tu faisais intervenir l'union. Lors de la réception (ie dans Receive_Data) ou ensuite pour traiter les données ?
Je ne suis pas sur de bien comprendre ce que tu cherches à dire par là.
Tu ne cherches tout de même pas à traiter une même valeur comme étant de différents types selon le contexte ?
Je suis entièrement d'accord qu'il ne faille pas gaspiller des ressources (mémoire ou autre). cependant, cette économie de mémoire ne doit pas être fait au détriment de la maintenabilité, de l'évolubilité, de la robustesse ou de la souplesse du programme comme cela a pu être fait lorsque la mémoire était une ressource vraiment rare.
En outre supposer que le programme devra tourner sur du matériel correspondant à la réalité du moment ce n'est pas tout à fait la même chose que "augmenter indéfiniment la mémoire disponible".
Comme indiqué précédemment, je répondais uniquement à l'interrogation de LittleWhite concernant la réutilisation de mémoire pour gagner de la place, pas à autre chose. Je ne vois pas où, dans mon message, j'ai parlé d'OO et donc ce qui te permet de tirer cette conclusion de mes propos.
Merci de ne pas me prêter des intentions qui ne sont pas les miennes, qui plus est sur des sujets qui ne sont pas aborder dans mes messages.
désolé si je me suis mal exprimé :oops: mon but n'était pas de te contredire mais d'ajouter à la discussion .. désolé..
Pour, l'OO, c'est moi qui en parlait pour expliciter mon propos pour LittleWhite.
Pour l'exemple, c'est dans le Receive_Data et ailleurs, juste pour stocker les valeurs.... dans les buffers, avec le type correct.
Je n'avais pas compris ta remarque vis-à-vis de la ré-utilisation...
tot va ben :D
Il n'y a pas de mal.
Juste une petite remarque au niveau terminologie : dans le cas de l'utilisation de l'union comme tu le fais, je parlerais de généricité plutôt que de POO.
En effet, même si couplé à d'autre mécanisme l'utilisation de l'union permet de faire de la POO en C, ce mécanisme (et donc cette généricité) peut être employée hors du cadre de la POO tout comme il peut être possible d'avoir une forme minimale de POO sans cette généricité.