Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Portabilités des unions

27 réponses
Avatar
Nicolas Maupu
Bonjour!

Une petite question me tarraude!
Est-ce que l'union est portable d'une architecture à une autre?
Typiquement, est-ce que le programme tournera sur un sparc comme sur un ix86
(sous le même OS)?

En effet, est-ce que sur certaines machines les poids forts/faibles ne
sont-ils pas inversés?

ex:
typedef union _u_int
{
int int_val;
char char_val[4];
}u_int;

Accède-t-on au premier octet de int_val par char_val[0], char_val[3]
ou ça dépend?

Merci.

--
Nico

10 réponses

1 2 3
Avatar
Jean-Marc Bourguet
Nicolas Maupu writes:

typedef union _u_int
{
int int_val;
char char_val[4];
}u_int;

Accède-t-on au premier octet de int_val par char_val[0], char_val[3]
ou ça dépend?


Acceder a un autre champs que le dernier dans lequel on a ecrit est
formellement du comportement indefini (sauf dans le cas tres
particulier d'une union de struct commencant par des membres de meme
type).

Et en pratique, pour une meme valeur dans int_val et pour une meme
valeur de sizeof(int), char_val[0] peut avoir des valeur differentes.

A+

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Patrick 'Zener' Brunet
Bonjour.

"Nicolas Maupu" a écrit dans le message de
news: d3govc$h3l$
Bonjour!

Une petite question me tarraude!
Est-ce que l'union est portable d'une architecture à une autre?
Typiquement, est-ce que le programme tournera sur un sparc comme sur un
ix86

(sous le même OS)?

En effet, est-ce que sur certaines machines les poids forts/faibles ne
sont-ils pas inversés?

ex:
typedef union _u_int
{
int int_val;
char char_val[4];
}u_int;

Accède-t-on au premier octet de int_val par char_val[0], char_val[3]
ou ça dépend?



L'union est portable, c'est ce que l'on peut en faire, ça en l'occurence,
qui ne l'est pas.

Vous ne pouvez pas faire tourner un code ainsi conçu pour un mapping "big
endian" sur une machine "little endian" et inversement : c'est la
portabilité conceptuelle qui entre en jeu.

Par contre vous pouvez imaginer de remplacer les indices 0 à 3 par des
constantes (macros) définies de manière adéquate par rapport à
"l'endianicité" de la plate-forme.

Au-delà (si le compilo le permet) vous pouvez même envisager (mais là plus
au niveau du préprocesseur) de déterminer cette caractéristique
automatiquement en utilisant une construction du même genre : mappez une
telle structure sur une constante de taille int et de valeur 1, et
considérez la valeur booléenne de char_val[0].
Mais en général cette information figure dans les headers standards, donc
une telle manoeuvre est inutile.

Il faut également se demander si un int est toujours de taille 32 bits. Là
aussi, en général il vaut mieux que le code se calibre sur les headers
standards dûment documentés par le fabricant du compilo.

Dans ces conditions, ça peut devenir 100% portable.

Cordialement,

--

/***************************************
* Patrick BRUNET
* E-mail: lien sur http://zener131.free.fr/ContactMe
***************************************/

Avatar
Emmanuel Delahaye
Nicolas Maupu wrote on 12/04/05 :
Une petite question me tarraude!
Est-ce que l'union est portable d'une architecture à une autre?


Tant qu'il s'agit de données internes, oui. (Sauf pratiques contre
nature que je n'ose même pas imaginer).

Typiquement, est-ce que le programme tournera sur un sparc comme sur un ix86
(sous le même OS)?

En effet, est-ce que sur certaines machines les poids forts/faibles ne
sont-ils pas inversés?

ex:
typedef union _u_int
{
int int_val;
char char_val[4];
}u_int;

Accède-t-on au premier octet de int_val par char_val[0], char_val[3]
ou ça dépend?


Argh! Y'a vraiment des pervers... Les unions ne doivent pas être
utilisées dans un mode non portable. On a pas le droit d'écrire dans un
élément et de lire dans un autre de la même union. C'est techniquement
possible, mais le résultat n'est pas défini par le langage C.

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"Mal nommer les choses c'est ajouter du malheur au
monde." -- Albert Camus.

Avatar
Nicolas Maupu
Accède-t-on au premier octet de int_val par char_val[0], char_val[3]
ou ça dépend?


Argh! Y'a vraiment des pervers... Les unions ne doivent pas être
utilisées dans un mode non portable. On a pas le droit d'écrire dans un
élément et de lire dans un autre de la même union. C'est techniquement
possible, mais le résultat n'est pas défini par le langage C.

Argh! Je vais devoir utiliser des décalages binaires alors! Car l'utilisation

que j'en faisais était d'accéder à un entier octet par octet...

--
Nico


Avatar
Emmanuel Delahaye
Nicolas Maupu wrote on 12/04/05 :
Argh! Je vais devoir utiliser des décalages binaires alors! Car l'utilisation
que j'en faisais était d'accéder à un entier octet par octet...


Les décalages binaires sont portables (entier non signés, bien sûr...)

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"C is a sharp tool"

Avatar
Nicolas Maupu
Argh! Je vais devoir utiliser des décalages binaires alors! Car l'utilisation
que j'en faisais était d'accéder à un entier octet par octet...


Les décalages binaires sont portables (entier non signés, bien sûr...)

Tant mieux!

Ouf, ce sont des entiers non signés!

Merci en tout cas, j'aurais pu avoir quelques soucis...

--
Nico


Avatar
Antoine Leca
Nicolas Maupu wrote:
Argh! Je vais devoir utiliser des décalages binaires alors!


Tu peux aussi utiliser un pointeur vers des char non signés: c'est la
manière conforme à la norme d'examiner byte par byte le contenu de n'importe
quel objet. Et sizeof aura le bon goût de te dire le nombre de bytes que tu
dois examiner.

Et évidemment, la plupart des entiers n'ont pas le même contenu sur une
plateforme petit-boutienne (x86) ou une gros-boutienne (Sparc).


Antoine

Avatar
Nicolas Maupu
Tu peux aussi utiliser un pointeur vers des char non signés: c'est la
manière conforme à la norme d'examiner byte par byte le contenu de n'importe
quel objet. Et sizeof aura le bon goût de te dire le nombre de bytes que tu
dois examiner.


Pas très pratique pour faire des additions, soustractions...

--
Nico

Avatar
Pierre Maurette
Tu peux aussi utiliser un pointeur vers des char non signés: c'est la
manière conforme à la norme d'examiner byte par byte le contenu de n'importe
quel objet. Et sizeof aura le bon goût de te dire le nombre de bytes que tu
dois examiner.


Pas très pratique pour faire des additions, soustractions...
Je ne vois pas trop la difficulté, par rapport à l'union et au décalage

de bits:

typedef uint8_t* pByte;
uint32_t Entier = 0x01020304;
pByte pbyte[4] = {(pByte)&Entier + 0
,(pByte)&Entier + 1
,(pByte)&Entier + 2
,(pByte)&Entier + 3
};
printf("%2Xt%2Xt%2Xt%2Xn", *pbyte[0], *pbyte[1], *pbyte[2],
*pbyte[3]);
printf("Somme: %dn", *pbyte[0] + *pbyte[1] + *pbyte[2] + *pbyte[3]);

(et plus lisible possible si vous aimez les maquereaux)


Pour en revenir à votre question initiale, quelques remarques:
- La norme est claire, les membres d'une union ne coexistent pas. Mais
...
- La norme garantit l'égalité des adresses de l'union et de chacun de
ses membres.
- A part le gain en mémoire (pas néglgeable), j'ai un peu l'impression
que les utilisations les plus intéressantes de l'union sont non
portables ;-).
- Quand vous écrivez qu'un int "contient" un char X[4], vous avez un
problème de poratbilité au moins aussi important qu'en détournant
l'union.
- Je suis à peu près convaincu que, si vous vous limitez à un nombre
fini de plateformes (x86, x86-64, Sparc par exemple), l'union comme
vous voulez l'utiliser ne vous emmerdera pas, contrairement à
l'assertion sur la taille de l'int.
- Dans tous les cas, l'endianité devra être prise en compte. Vous
pouvez la détecter grâce au procédé que vous allez utiliser (le code
ci-dessus affiche en quelque sorte un diagnostic d'endianité).

Une question, souhaitez-vous accèder à votre int par char ou par octet
?
--
Pierre

--
Ceci est une signature automatique de MesNews.
Site : http://www.mesnews.net


Avatar
Antoine Leca
Pierre Maurette wrote:
- A part le gain en mémoire (pas néglgeable), j'ai un peu l'impression
que les utilisations les plus intéressantes de l'union sont non
portables ;-).


L'utilisation portable de l'union, c'est... le pendant des enregistrement
variants du Pascal (et de plusieurs autres langages): une première partie
commune à tous les sous-types, qui contient les discriminants; puis des
sous-parties (se recouvrant) pour chacun des différents sous-types.

Le truc sympa, c'est qu'avec un pointeur vers l'union, disons passé en
argument, on peut (légalement, enfin portablement) examiner les
discriminants, puis transtyper correctement et accéder aux éléments de la
sous-partie qui correspond à ce qui a été rangé réellement dans l'union
passée comme paramètre. Le degré de base du polymorphisme, mais c'est
amplement suffisant pour plein plein de choses.


- Je suis à peu près convaincu que, si vous vous limitez à un nombre
fini de plateformes (x86, x86-64, Sparc par exemple), l'union comme
vous voulez l'utiliser ne vous emmerdera pas,


ÀMHA, là tu t'avances... Le Sparc est gros-boutien, je crois...

D'ailleurs, tu écris ensuite...

- Dans tous les cas, l'endianité devra être prise en compte.


... et cela suffit en général à faire que les utilisations un peu trop
tangentes des unions deviennent caduques.


Une question, souhaitez-vous accèder à votre int par char ou par
octet ?


Taquin, va...


Antoine

1 2 3