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

Union de deux tableaux 4x4 et 1x16

14 réponses
Avatar
Thierry B.
Bonjour le monde.

Question simple, avec un ECM:

-----------------------------------------------
#include <stdio.h>
typedef union
{
char s[4][4];
char l[16];
} machin;
int main(int argc, char *argv[])
{
int x, y, i;
machin m;
/* remplir le machin */
for (i=0; i<16; i++)
m.l[i] = i;
/* afficher le machin */
for (x=0; x<4; x++)
{
for (y=0; y<4; y++)
printf("%2d ", m.s[x][y]);
puts("");
}
return 0;
}
-----------------------------------------------

Ai-je raison de penser que ces deux façons de voir un bloc de
seize petits nombres est portable sur une grande majorité de
trucs, et que dans les deux cas, je peux supposer que le
compilateur saura faire les optimisations qui vont bien ?

tTh.


--
> parce que maintenant linux tue tous les processus pour libérer de la
> mémoire, DONC pas de soucis hein ?
bah, il suffit d'augmenter la mémoire disponible avec
dd if=/dev/zero bs=1024 count=$((1024 * 512)) >> /dev/kcore

4 réponses

1 2
Avatar
Thierry B.
--{ Erwan David a plopé ceci: }--


Euh, juste une question idiote: comment traduire "This may be a trap
representation" ?


Une "trap representation" c'est une suite de bits qui ne représente pas
une valeur du type et qui provoque donc une exception si on tente de
l'utiliser. Je ne conaias pas le terme français.

Moi non plus, et c'est pas simple à traduire :) Ceci dit,

mon code semble marcher, et j'espère que c'est pas dû au
hasard.

A bientôt pour d'autres questions idiotes.

--
- Ne buvez pas au volant, buvez à la bouteille.


Avatar
Pierre Maurette

[...]

Bon, d'un autre coté, comme il me semble bien, d'après ce que j'ai
pu comprendre, qu'un tableau [4][4] serait représenté en mémoire
de la même façon qu'un tableau [16], je pense que mes "relevant
bytes" sont à la bonne place. Pour le moment, ça marche, mais je
n'ai pas essayé avec autre chose que Gcc...


Il n'y a pas de problème de représentation mémoire, votre démarche est
de ce coté-là correcte. Sans entrer dans les détails, il suffit de
constater que l'adresse de tous les membres d'une union est l'adresse
de l'union, adresse que l'on peut prendre indépendamment de tout accès
à un membre. Ensuite, les règles assez strictes d'implantation des
tableaux en mémoire font le reste.
Pour ce qui est du comportement des compilateurs face à un accès à plus
d'un membre de l'union, je serais plutôt optimiste, au motif qu'il me
semble bien que le truc est assez fréquent dans le code existant.
Ceci dit, je ne vois pas nécessairement l'avantage d'utiliser une
union. Certes on ne peut pas transtyper un tableau, mais on peut tout à
fait transtyper un pointeur. Ça vous donnerait un truc genre:

#include <stdio.h>

int main()
{
int x, y, i;
char m[16];
/* remplir le machin */
for (i=0; i<16; i++)
m[i] = i;
/* afficher le machin */
for (x=0; x<4; x++)
{
for (y=0; y<4; y++)
printf("%2d ", (*(char(*)[4][4])&m)[x][y]);
puts("");
}
return 0;
}


ou:


#include <stdio.h>

int main()
{
int x, y, i;
char m[4][4];
/* remplir le machin */
for (i=0; i<16; i++)
*((char*)&m + i) = i;
/* afficher le machin */
for (x=0; x<4; x++)
{
for (y=0; y<4; y++)
printf("%2d ", m[x][y]);
puts("");
}
return 0;
}

ou encore, un truc plus général qui pourrait être fluidifié par des
typedef-ages de tableaux:

#include <stdio.h>

int main()
{
int x, y, i;
char m[16];
void* p = &m; /* Ou n'importe quelle initialisation d'un void* */
char (*l)[16] = p;
char (*s)[4][4] = p;
#define L (*l) /* Peu utile et sans doute cacabeurk */
#define S (*s) /* Peu utile et sans doute cacabeurk */
/* remplir le machin */
for (i=0; i<16; i++)
L[i] = i;
/* afficher le machin */
for (x=0; x<4; x++)
{
for (y=0; y<4; y++)
printf("%2d ", S[x][y]);
puts("");
}
#undef L
#undef S
return 0;
}

--
Pierre Maurette

Avatar
espie
In article <483ffd95$0$14551$,
candide wrote:

C'est un tantinet beurk,


En quoi c'est beurk ?



mais je pense que c'est portable sur toutes
les implementations conformes a la norme, en C89 comme C99...


Donc, on ne serait pas dans ce cas (extrait de C89, §6.3.2.3)

---------------- 8< -------------------------
With one exception, if a member of a union object is accessed after
a value has been stored in a different member of the object, the
behavior is implementation-defined.
---------------- >8 -------------------------

Je ne retrouver pas d'equivalent a ce paragraphe dans C99.


Les regles qui s'appliquent dans le cas qui nous interessent sont dans
6.5.2.3, paragraphe 5.


Avatar
espie
In article <g1pb8u$uc5$,
Antoine Leca wrote:
En news:483ffd95$0$14551$, candide va escriure:

C'est un tantinet beurk,


En quoi c'est beurk ?


Ce n'est pas qosher (strictement conforme si tu préfères).


mais je pense que c'est portable sur toutes
les implementations conformes a la norme, en C89 comme C99...


Donc, on ne serait pas dans ce cas (extrait de C89, §6.3.2.3)
---------------- 8< -------------------------
With one exception, if a member of a union object is accessed after
a value has been stored in a different member of the object, the
behavior is implementation-defined.
---------------- >8 -------------------------


Vous me semblez parler de deux choses différentes.
Marc répond à la question originale, « est-ce que mon truc va marcher sur la
quasi-totalité des implémentations » (dans le texte de la norme, c'est le
sens qu'aurait dû avoir « conforme », s'il était possible de spécifier ce
sens) ; et propose de répondre oui.


Non, en l'occurrence, quand je dis portable, ca voulait dire parfaitement
defini... je n'ai pas retrouve de C89, mais apres examen de C99, il y a
peut-etre un petit os.

Les regles qui s'appliquent concernent la representation des tableaux,
qui confirment que les deux representations de l'union vont se correspondrent
membre a membre, plus les regles d'aliasing, qui disent que tout marche bien
*membre a membre* si les membres se correspondent, et le paragraphe specifique
aux unions (6.5.2.3.5).

Celui-ci pose probleme, je pense que les deux membres d'union ne sont
pas dans le cas `share a common initial sequence'. En effet, il n'y a
pas de regles regissant `compatible types' pour des tableaux qui possedent
des declarations differentes (confere 6.2.7)

Ca me semble d'ailleurs un defaut de la norme, puisqu'on ne peut pas
construire deux types tableaux qui s'appuient sur des types compatibles
et les garder compatibles (ouch).

Donc a l'arrivee, sauf si j'ai rate un paragraphe, je concluerais de
facon moins rapide que ce code est, ni conforme, ni strictement conforme,
fonctionne sur la plupart des compilateurs par accident, et est donc
a eviter.

De toutes facons, rien que les endroits peu intuitifs ou il faut fouiller
dans la norme pour savoir si ce machin est ou non bien defini indiquent
assez clairement qu'au moins certains des vendeurs de compilo interpreteront
la norme de facon differente, et qu'il vaut mieux eviter ce genre de
construction. C'est une bombe a retardement: au fil des annees, au fur
et a mesure que les compilateurs deviennent plus sophistiques, on a de
plus en plus d'optimisation qui se reposent sur des analyses fines de
typage... Tot ou tard, ce genre de trucs sera optimise de travers, avec
arrachage de cheveux en perspective. Ces types de bug sont parmi les
pires a trouver, puisque ce sont des problemes d'optimisation globale,
qui apparaissent disparaissent lorsqu'on modifie `autre chose' dans le
code, tres souvent a plusieurs centaines de lignes de distance...



1 2