Problème avec bsearch()

Le
JKB
Bonjour à tous,

J'ai un petit problème avec bsearch(), la fonction de comparaison
me renvoyant un segfault. Avant de poster ici, j'ai naturellement
vérifié avec valgrind qu'il n'y avait pas de corruption mémoire,
je n'ai rien trouvé. La même fonction de comparaison fonctionne
parfaitement (sur le même tableau) avec qsort().

J'ai écrit ceci :

static int
fonction_comparaison(const void *argument_1, const void *argument_2)
{
return(strcmp((unsigned char *) (**((struct_objet **) argument_1)).objet,
(unsigned char *) (**((struct_objet **) argument_2)).objet));
}

Le prototype de struct_objet est le suivant :
typedef struct objet
{
enum t_type type;
integer8 extension_type;
void *descripteur_bibliotheque;
volatile long nombre_occurrences;
pthread_mutex_t mutex;
void *objet;
} struct_objet;

Seul nous intéresse ici le pointeur sur le void. En l'occurence,
lorsque l'objet contient une chaîne de caractère, ce pointeur est un
pointeur sur un unsigned char *.

Lorsque cet objet est un tableau, le pointeur tape sur une structure
struct_tableau définie comme :

typedef struct tableau
{
integer8 nombre_elements;
struct_objet **elements;
} struct_tableau;

Le type integer8 est un entier 64 bits.

Le bout de code en question crée un objet tableau contenant
quatre chaînes de caractères.

On a donc une structure S :

struct_objet -> struct_tableau -> elements(4)

Je réécris les fonctions qui posent problème. Il peut s'être
glissées des coquilles car j'ai simplifié les expressions (les
structures en mémoire sont beaucoup plus complexes que cela).

qsort(((struct_tableau *) S->objet)->elements,
(size_t) ((struct_tableau *) S->objet)->nombre_elements,
sizeof(struct_objet *),
fonction_comparaison);

Ce tri fonctionne parfaitement et mon tableau est trié. Je
l'initialise pour mon test avec "key" "value" "i" "j", qsort()
retourne "i" "j" "key" "value".

J'essaie d'accéder à un élément particulier en utilisant bsearch() à
partir d'une autre fonction. J'utilise donc la même fonction
de comparaison. Avant d'appeler bsearch(), je vérifie que le contenu
de mon tableau est bon :

(indice->adresse (chaîne))

0->0x559c5070b3c8 (i)
1->0x559c50712958 (j)
2->0x559c506f0a38 (key)
3->0x559c506f09f8 (value)
0x559c506f0a38->key

Cette sortie est faite par :

for(i = 0; i < ((struct_tableau *) S->objet).nombre_elements;
printf("%d->%p (%s)", i,
(unsigned char *) ((struct_tableau*) S->objet)->elements[i])->objet,
(unsigned char *) ((struct_tableau*) S->objet)->elements[i])->objet,
i++);

Le nombre d'éléments est correct, le contenu des chaînes est bon.
Valgrind ne rale pas.

J'appelle donc bsearch() de la manière suivante (clef est
initialisée un peu plus haut) :

s_objet_element = bsearch((unsigned char *) clef,
((struct_tableau *) S->objet)->elements,
(size_t) ((struct_tableau *) S->objet)->nombre_elements,
sizeof(struct_objet *), fonction_comparaison);

Et je me tape un segfault dans la fonction de comparaison. J'ai donc
investigué un peu plus loin en regardant les adresses passées à
cette fonction.

Lors du premier appel de la fonction de comparaison, le second
argument semble bon (il pointe sur l'une de mes chaînes) :

0x559c506f0a38->key

En revanche, le premier argument pointe sur n'importe quoi :

0x41048c200e47038d->Trying to catch access violation

Le message "Trying to catch access violation" provient du
gestionnaire de signaux.

Là, je ne comprends pas. J'ai beau reprendre les arguments de
bsearch(), je passe bien dans l'ordre la clef, le pointeur sur la
base du tableau, le nombre d'éléments du tableau, la taille de
chaque élément et un pointeur sur la fonction de comparaison. Et les
types sont les bons.

Je sèche. Toute idée sera la bienvenue.

Bien cordialement,

JKB

--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse
=> http://grincheux.de-charybde-en-scylla.fr
=> http://loubardes.de-charybde-en-scylla.fr
Vos réponses Page 2 / 2
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Samuel DEVULDER
Le #26502822
Le 22/12/2018 à 15:22, Pascal J. Bourguignon a écrit :
Enfin, pour s'en sortir, surtout avec du code legacy, il faut absolument
introduire des abstraction fonctionnelles, et ne surtout pas utiliser
partout des accès aux structures et des casts!

Méfiance!! Comme je le dis concernant du code légacy: on ne répare pas
un code qui marche. Le mieux est l'ennemi du bien!
Souvent en faisant mieux, on obtient bien pire parce qu'on considère
comme mieux actuellement n'est pas forcément adapté au codes et aux
machines de l'époque. Exemple: un GC c'est bien de nos jours, mais sur
un ordi monocoeur il bloquera l’exécution de façon imprédictible ce qui
posera des soucis avec un traitement "temps réel".
a+
sam.
---
L'absence de virus dans ce courrier électronique a été vérifiée par le logiciel antivirus Avast.
https://www.avast.com/antivirus
Pascal J. Bourguignon
Le #26502836
Samuel DEVULDER
Le 22/12/2018 à 15:22, Pascal J. Bourguignon a écrit :
Enfin, pour s'en sortir, surtout avec du code legacy, il faut absolument
introduire des abstraction fonctionnelles, et ne surtout pas utiliser
partout des accès aux structures et des casts!

Méfiance!! Comme je le dis concernant du code légacy: on ne r épare pas
un code qui marche. Le mieux est l'ennemi du bien!
Souvent en faisant mieux, on obtient bien pire parce qu'on considère
comme mieux actuellement n'est pas forcément adapté au codes et aux
machines de l'époque. Exemple: un GC c'est bien de nos jours, mais s ur
un ordi monocoeur il bloquera l’exécution de façon impr édictible ce
qui posera des soucis avec un traitement "temps réel".

On parle de code legacy, pas d'ordinateur legacy.
S'il s'agit de faire tourner de vielles machines, c'est sur, on ne va
pas pouvoir moderniser beaucoup le logiciel. Déjà, il n'y aura p as les
outils, ou ça va être une galère pour compiler les outils r écents sur
les vieux systèmes, avec toutes les dépendences, etc.
Mais reprendre du vieux code sur un système moderne, dans la mesure des
besoins, on peu le faire évoluer drastiquement.
Le seul cas où c'est difficile, c'est quand on veut du bogue-pour-bogu e,
car il est en effet facile d'éliminer beaucoup de bogues en le faisant
évoluer proprement…
--
__Pascal J. Bourguignon__
http://www.informatimago.com
espie
Le #26502874
In article Pascal J. Bourguignon
Samuel DEVULDER
Le 22/12/2018 à 15:22, Pascal J. Bourguignon a écrit :
Enfin, pour s'en sortir, surtout avec du code legacy, il faut absolument
introduire des abstraction fonctionnelles, et ne surtout pas utiliser
partout des accès aux structures et des casts!

Méfiance!! Comme je le dis concernant du code légacy: on ne répare pas
un code qui marche. Le mieux est l'ennemi du bien!
Souvent en faisant mieux, on obtient bien pire parce qu'on considère
comme mieux actuellement n'est pas forcément adapté au codes et aux
machines de l'époque. Exemple: un GC c'est bien de nos jours, mais sur
un ordi monocoeur il bloquera l’exécution de façon imprédictible ce
qui posera des soucis avec un traitement "temps réel".

On parle de code legacy, pas d'ordinateur legacy.
S'il s'agit de faire tourner de vielles machines, c'est sur, on ne va
pas pouvoir moderniser beaucoup le logiciel. Déjà, il n'y aura pas les
outils, ou ça va être une galère pour compiler les outils récents sur
les vieux systèmes, avec toutes les dépendences, etc.
Mais reprendre du vieux code sur un système moderne, dans la mesure des
besoins, on peu le faire évoluer drastiquement.
Le seul cas où c'est difficile, c'est quand on veut du bogue-pour-bogue,
car il est en effet facile d'éliminer beaucoup de bogues en le faisant
évoluer proprement…

Generalement, si c'est du vrai code, ca va commencer par utiliser des
techniques modernes de developpement, donc passer pas mal de temps a
ecrire des tests unitaires et des tests d'integration ;)
Samuel DEVULDER
Le #26502915
Le 24/12/2018 à 02:30, Pascal J. Bourguignon a écrit :
On parle de code legacy, pas d'ordinateur legacy.

Le "on ne répare pas un truc qui marche" et "le mieux est l'ennemi du
bien" s'appliquent dans les deux cas. Combien de fois n'ai-je pas vu un
logiciel moins bien marcher suite à une mise à jour... Et tout ca pour
faire "mieux"... Moauis...
sam.
---
L'absence de virus dans ce courrier électronique a été vérifiée par le logiciel antivirus Avast.
https://www.avast.com/antivirus
David Larochette
Le #26502932
Le 22-12-2018, JKB
si j'avais le temps, je
réécrirais cette application dans un langage plus approprié que le C. Au
hasard, le C++
JKB

Dis, ça va ? Tu nous couves pas quelque-chose ?
Samuel DEVULDER
Le #26503042
Le 22/12/2018 à 23:24, JKB a écrit :
je
réécrirais cette application dans un langage plus approprié que le C. Au
hasard, le C++

$ cat c_vs_cxx.c
#include void main(void) {
int c=3;
printf("c=%dn", c);
printf("c++=%dn", c++);
}
$ cc c_vs_cxx.c
$ ./a.out
c=3
c++=3
$ exit
Humm de ce que j'en vois, même si on a l'impression d'avoir un coup
d'avance avec le c++, en pratique c et c++ valent la même chose...
sam :D
---
L'absence de virus dans ce courrier électronique a été vérifiée par le logiciel antivirus Avast.
https://www.avast.com/antivirus
Pascal J. Bourguignon
Le #26503044
Samuel DEVULDER
Le 22/12/2018 à 23:24, JKB a écrit :
je
réécrirais cette application dans un langage plus approprié que le C. Au
hasard, le C++

$ cat c_vs_cxx.c
#include void main(void) {
int c=3;
printf("c=%dn", c);
printf("c++=%dn", c++);
}
$ cc c_vs_cxx.c
$ ./a.out
c=3
c++=3
$ exit
Humm de ce que j'en vois, même si on a l'impression d'avoir un coup
d'avance avec le c++, en pratique c et c++ valent la même chose...
sam :D

Il doit y avoir une bogue. J'obtiens ça comme résultat:
#include void main(void) {
int c=3;
int cpp=c++;
printf("c++ = %dn", cpp);
printf("c = %dn", c);
printf("c %s c++n", (c<cpp)?"<":((c>cpp)?">":"=="));
}
-*- mode: compilation; default-directory: "~/src/c/" -*-
Compilation started at Thu Dec 27 00:21:15
SRC="/Users/pjb/src/c/c-vs-c++.c" ; EXE="c-vs-c++" ; gcc -I. -L. -g3 -ggdb3 -o ${EXE} ${SRC} && ./${EXE} && echo status = $?
c++ = 3
c = 4
c > c++
Compilation exited abnormally with code 8 at Thu Dec 27 00:21:16
--
__Pascal J. Bourguignon__
http://www.informatimago.com
Samuel DEVULDER
Le #26503058
Le 27/12/2018 à 00:22, Pascal J. Bourguignon a écrit :
Il doit y avoir une bogue.

hmm... voyons...
J'obtiens ça comme résultat:
#include void main(void) {
int c=3;
int cpp=c++;
printf("c++ = %dn", cpp);
printf("c = %dn", c);
printf("c %s c++n", (c<cpp)?"<":((c>cpp)?">":"=="));
}

Normal, c'est pas le même programme, il ne fait absolument pas la même
chose. Je ne le redirais jamais assez: On ne réparer pas un truc qui
marche, sinon a on toutes les chances d'introduire des bugs, ce qui est
le cas ici.
a+
sam ;)
---
L'absence de virus dans ce courrier électronique a été vérifiée par le logiciel antivirus Avast.
https://www.avast.com/antivirus
espie
Le #26503086
In article David Larochette
Le 22-12-2018, JKB
si j'avais le temps, je
réécrirais cette application dans un langage plus approprié que le C. Au
hasard, le C++
JKB

Dis, ça va ? Tu nous couves pas quelque-chose ?

Mort de rire!
Publicité
Poster une réponse
Anonyme