OVH Cloud OVH Cloud

Implementation de qsort

76 réponses
Avatar
candide
Bonjour !

Plauger implémente qsort en déclarant un tableau local d'une taille de
256 bytes. Ce tableau sert à faire des transpositions (swap) de clés.
Mais comme la taille size des données est inconnue, le code doit, le cas
échéant s'y prendre en plusieurs fois pour terminer le swap, ce qui doit
être assez couteux. Alors je me demandais pourquoi il n'avait pas décidé
d'utiliser malloc pour éviter toutes ses contorsions. Quelque chose dans
la norme l'interdit-t-il ? En plus, il s'agirait d'allouer juste une
fois un buffer dynamique qui permet de faire un swap de façon classique.

6 réponses

4 5 6 7 8
Avatar
Erwan David
(Marc Espie) écrivait :

In article <492ff34f$0$6827$,
candide wrote:
Pourtant, j'ai l'impression que dans la pratique on se donne beaucoup
plus de liberté pour faire des conversions de pointeurs, enfin, je vais
surveiller ça avec attention dans le code qui me passera sous les yeux.



Non, pas dans du code portable.

Par contre, C te garantit que si tu as
struct A {
int a;
} *p;

alors tu peux faire (int *)p et dereferencer le resultat et tomber sur le
champ a.

Bref, ce qui est important, ce sont les valeurs scalaires. Une bonne partie
de l'enrobage (struct) que tu mets autour n'a que peu d'importance, et on
te fournit meme des mecanismes, comme offsetof, pour te garantir que tu
vas pouvoir retomber sur tes pattes.



Sur une implémentation conforme...

Je connais une plateforme où les long (32 bits) doivent être alignés,
mais où
union{
long a;
char bytes[5];
};

peut se retrouver à une adresse impaire...

--
Le travail n'est pas une bonne chose. Si ça l'était,
les riches l'auraient accaparé
Avatar
Antoine Leca
En news:492ff34f$0$6827$, candide va escriure:
Antoine Leca a écrit :

Écrire du code strictement conforme, ou ce qui revient au même le
plus portable possible. Donc, si tu suis la norme, éviter les
conditions de comportement indéfini, ainsi que les comportements non
spécifiés ou définis par l'implémentation ayant un impact sur les
productions du programme (clause 4 alinéa 5).



OK mais concernant l'alignement, la norme ne dit pas grand chose, Dans
l'annexe J2, il n'y a que

Conversion between two pointer types produces a result that is
incorrectly aligned (6.3.2.3).



C'est déjà beaucoup...


ce qui n'avance guère puisque l'alignement n'est pas défini comme un
comportement défini par l'implémentation (il est juste question de
l'alignement des champs de bits).



Ici cela ne parlait pas d'alignement mais de conversions entre des types
pointeurs. Et si tu veux du code le plus portable possible, bien c'est
simple, il faut qu'il n'y ait pas de conversions de types pointeurs (à cause
des problèmes d'alignement).


Pourtant, j'ai l'impression que dans la pratique on se donne beaucoup
plus de liberté pour faire des conversions de pointeurs, enfin, je
vais surveiller ça avec attention dans le code qui me passera sous
les yeux.



Si tu veux dire qu'une très grande portion du code C « utile » n'est pas
strictement conforme donc pas totalement portable dans l'esprit de la norme,
il faut dire qu'il y a un peu de cela.


However, C does give the programmer the ability to violate alignement
restriction by casting pointers to differnt types.

ce qui me laisse vraiment sur ma faim.



Dommage n'est-ce pas, H&B disent en gros la même chose que les gens qui
fréquentent ce groupe...
D'un autre côté, cela devrait te rassurer, non ?


Antoine
Avatar
Antoine Leca
En news:ggotab$1r6o$, Marc Espie va escriure:
Par contre, C te garantit que si tu as
struct A {
int a;
} *p;

alors tu peux faire (int *)p et dereferencer le resultat et tomber
sur le champ a.



Je crois que tu n'as la garantie en question QUE si tu accèdes au champ a à
l'intérieur d'une structure (car tous les pointeurs vers structures doivent
avoir les mêmes restrictions d'alignement etc. c'est fait exprès pour
utiliser des types anonymes ou polymorphes et cie.)

Par contre, si tu tire directement avec un int* c'est moins clair pour moi.
Même si dans les faits, je ne vois pas de raisons pratique pour que cela
pose des problèmes dans ce sens-là.

Évidemment, je vois bien pourquoi le contraire pourrait ne pas marcher: si
je prend une adresse d'objet char quelconque, donc un char* p, et j'essaye
de l'utiliser comme (struct s*)p avec
struct s { char c ; };
cela peut foirer, en particulier sur les machines où les pointeurs vers char
sont plus gros que les pointeurs vers structures.


Antoine
Avatar
Jean-Marc Bourguet
"Antoine Leca" writes:

En news:ggotab$1r6o$, Marc Espie va escriure:
> Par contre, C te garantit que si tu as
> struct A {
> int a;
> } *p;
>
> alors tu peux faire (int *)p et dereferencer le resultat et tomber
> sur le champ a.

Je crois que tu n'as la garantie en question QUE si tu accèdes au champ a à
l'intérieur d'une structure (car tous les pointeurs vers structures doivent
avoir les mêmes restrictions d'alignement etc. c'est fait exprès pour
utiliser des types anonymes ou polymorphes et cie.)

Par contre, si tu tire directement avec un int* c'est moins clair pour moi.
Même si dans les faits, je ne vois pas de raisons pratique pour que cela
pose des problèmes dans ce sens-là.



J'ai pas le temps de retrouver, mais je suis quasiment certain qu'il y a
bien une garantie formelle qu'on peut caster un pointeur vers une structure
en un pointeur vers le type son premier champs et optenir ainsi un pointeur
vers le premier champs et un pointeur vers le premier champs d'une
structure en un pointeur vers le type de la structure et optenir ainsi un
pointeur vers la structure.

Je ne comprends pas ta remarque entre parenthese. Tous les pointeurs vers
des structures doivent avoir la meme representation, mais je ne vois pas
pourquoi les restrictions d'alignement doivent etre les memes. Avec

struct a {
char c;
};

struct b {
double d;
};

ca imposerait que struct a* et struct* b ont le meme alignement donc que
struct a a pour taille un multiple de 8 sur pas mal d'architectures. J'en
doute fort (j'ai d'ailleurs une sparc sous la main ou sizeof(struct a) est
1).

A+

--
Jean-Marc
FAQ de fclc: http://www.levenez.com/lang/c/faq
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Avatar
Erwan David
"Antoine Leca" écrivait :

En news:, Erwan David va
escriure:
Je connais une plateforme où les long (32 bits) doivent être alignés,
mais où
union{
long a;
char bytes[5];
};

peut se retrouver à une adresse impaire...



Waou !

Et si on a un objet u de cette union placé à une adresse impaire ou non
multiple de 4, le compilo (et le processeur) accepte-t-il d'accéder à a.u
sans broncher (ou : comment contourner les restrictions d'alignement ;-> ),
ou te jette-t-il sans vergogne ni solutions de repli ?



Le compilo accepte, pas le processeur... Mais bon, vu le nombre de bugs
de ce style que j'ai remonté, il doit être très peu utilisé (et plus par
moi maintenant)

--
Le travail n'est pas une bonne chose. Si ça l'était,
les riches l'auraient accaparé
Avatar
-ed-
On 27 nov, 01:06, candide wrote:

OK mais le problème c'est que je suis pas censé connaitre les
contraintes d'alignement de telle ou telle cible. Donc que dois-je faire
pour être sûr de ne pas produire de code violant une contrainte
d'alignement ? Le compilateur est pourtant capable de gérer l'alignemen t
puisque par exemple les objets créés par malloc sont correctement
alignés, la norme l'assure :



Il n'y a pas de problèmes tant qu'on ne joue pas avec les pointeurs et
les cast comme le l'ai montré. Si on écrit du code propre, ça n'arriv e
pas. Ce sont certains esprits forts qui se croient malins en voulant à
tout prix violer les règles à coup de cast de barbares qui se
retrouvent le nez dans le gazon... Un programmeur C bien formé ne fait
pas ça.

Donc, comment puis-je savoir si ma conversion ne va pas engendrer une
erreur d'alignement, après tout les conversions d'un pointeur de type T 1
 en un pointeur de type T2 distinct de T1 ne sont pas rares ?



Ah ? Pourquoi ferais-tu ça ?

Ce qui est garanti c'est T* -> void* -> T*

mais pas pas T1* -> void* -> T2*. Le comportement est indéfini.

OK mais dans la pratique, les cas où a besoin de faire ce genre
d'écritures sauvages sont assez rares je suppose.



Si on sait coder, ça n'arrive pas.
4 5 6 7 8