Erreur: undefined reference to `seek' (Modification fichier bmp) - C - Programmation
Marsh Posté le 21-10-2007 à 10:34:28
T'aurais pas simplement ecrit "seek" au lieu de "fseek" ... ?
edit pour l'explication: quand ton compilo tombe sur une fonction qu'il ne connait pas, alors il suppose qu'elle renvoie un int et que tous ses parametres sont des int. Dans ton .o, il y a donc des references vers cette fonction qui sont faites. Mais si la fonction n'existe pas (dans un autre .o ou dans une bibliotheque), alors les references ne vont pas pouvoir etre resolues, et ca va te donner des erreurs a l'edition de liens.
Marsh Posté le 21-10-2007 à 10:41:01
Ace17 a écrit : T'aurais pas simplement ecrit "seek" au lieu de "fseek" ... ? |
Je suis con et pas fier de l'air
Vraiment un grand merci Ace17 pour m'avoir branché le cerveau en ce bon matin!
Edit: ok merci également pour les précisions ça m'aide beaucoup à comprendre. J'ai recompilé et ça marche! En plus j'arrive enfin à rendre une image négative dans un délai raisonnable. (d'ailleurs c'est dur de trouver un compromis vitesse/nbre de vérifications des erreurs)
Marsh Posté le 21-10-2007 à 12:15:58
Bon voilà ce que j'obtiens en 37sec (et là je me dit que je ne pesterai plus contre photoshop quand il rame alors que moi c'est pire ) sur un bmp de 900x513:
=>
Comme vous pouvez le voir il y a des points bleu qui apparaissent c'est intéressant. Je vais voir pourquoi.
Je me demande quels algorithme ils utilisent dans les logiciels, c'est là que je me rends compte qu'ils sont très rapide.
Marsh Posté le 21-10-2007 à 13:07:02
Ton programme est lent parce qu'il passe son temps a faire des seek/fread/fwrite. Dans l'ideal on charge le bitmap completement en memoire (avec un seul fread), on le modifie, et on le reecrit sur le disque (avec un seul fwrite). Fais ca, et tu vas voir que tu vas enormement gagner en rapidite.
Marsh Posté le 21-10-2007 à 13:10:34
Ace17 a écrit : Ton programme est lent parce qu'il passe son temps a faire des seek/fread/fwrite. Dans l'ideal on charge le bitmap completement en memoire (avec un seul fread), on le modifie, et on le reecrit sur le disque (avec un seul fwrite). Fais ca, et tu vas voir que tu vas enormement gagner en rapidite. |
Ah oui c'est vrai! Merci je vas faire ça.
Marsh Posté le 21-10-2007 à 13:20:49
Attention, tu as oublié l'appel à fclose(). Vérifie également que tu as bien pu ouvrir le fichier comme tu le voulais.
Marsh Posté le 22-10-2007 à 15:34:32
Ok merci pour la précision.
Sinon j'ai compris mon erreur, mais je ne comprends pas pourquoi ma fonction fonctionnait dans un cas mais pas dans l'autre:
Celle là ne fonctionnait pas:
Code :
|
Celle là si:
Code :
|
Et dans le premier cas pourquoi ça ne marchais pas quand le nombre de pointeurs dans ma structure nouvo_type était supérieur à 2?
Marsh Posté le 22-10-2007 à 15:52:28
ReplyMarsh Posté le 22-10-2007 à 15:53:30
Tu écrit un octet dans un entier... Il faut lire sizeof tmp, pas 1.
Edit : enfin puisque tu veux lire un octet, lit un octet, mais met-le dans une variable de type char, pas int.
Marsh Posté le 22-10-2007 à 15:54:11
ReplyMarsh Posté le 22-10-2007 à 15:54:35
Taz a écrit : man fread. |
man quésaco?
A quel niveau je l'ai mal utilisé? Pour savoir vers où chercher.
Marsh Posté le 22-10-2007 à 15:55:49
fread a des arguments, ils ont un sens. Ouvre ton manuel et corrige celui qui est défectueux.
Marsh Posté le 22-10-2007 à 15:58:44
ngkreator a écrit : |
man = 'manual' (manuel)
Par exemple :
http://man.developpez.com/
ou
* man fonction |
sous unixoïde ou Cygwin (Windows).
Marsh Posté le 22-10-2007 à 16:22:03
matafan a écrit : Tu écrit un octet dans un entier... Il faut lire sizeof tmp, pas 1. |
Je comprends, étant donné que char stocke un seul octet ça me parait logique au final. Mais ça porte pas à confusion le fait d'utiliser char pour une valeur numérique? Mais au moins ça ne gaspille pas le 2ème 'octet qui ne sert pas avec int ok.
Taz a écrit : Juste en passant ... |
Ah oui d'accord. Donc apparemment il aurai ajouté la valeur tout simplement. Mais sinon je comprends pas pourquoi ça serait affiché en hexadécimal si dans mon printf j'ai mis %d?
Emmanuel Delahaye a écrit :
|
Ok, bien sur je suis allé voir à plusieurs endroits comme ici par ex: http://www.cplusplus.com/reference [...] fread.html
Il y a de très bon cours en pdf aussi, je les ai consultés.
Pour l'instant je ne vois pas où je me trompé dans l'utilisation de fread mais je vais revoir les docs.
Marsh Posté le 22-10-2007 à 16:25:40
ngkreator a écrit : Je comprends, étant donné que char stocke un seul octet ça me parait logique au final. Mais ça porte pas à confusion le fait d'utiliser char pour une valeur numérique? Mais au moins ça ne gaspille pas le 2ème 'octet qui ne sert pas avec int ok. |
Si tu veux lire un char, utilise un char. Si tu utilises un int, lis un int.
Trop bien ton économie de 3 octets, tu devrais postuler à la NASA.
Un char est une sorte d'entier. Le seul truc c'est qu'a travailler en char, ça peut se réveler une contre-optimisation.
Marsh Posté le 22-10-2007 à 16:37:44
Taz a écrit : Si tu veux lire un char, utilise un char. Si tu utilises un int, lis un int. |
Le problème c'est que je veux lire 1 octet. Je le stocke dans un char ou un int ça marche pour les deux. Après je pensais juste que le type int portait moins à confusion, quand on lit le programme, que le type char pour stocker un octet.
Super ta remarque pour la NASA j'ai juste essayé de trouver une raison pour laquelle il me disait d'utiliser char au lieu de int.
Marsh Posté le 22-10-2007 à 16:43:05
ngkreator a écrit : Le problème c'est que je veux lire 1 octet. Je le stocke dans un char ou un int ça marche pour les deux. |
Stockage != lecture. Même remarque que précédemment. man fread. Là tu lis un byte qui écrit partiellement un int. C'est mauvais. Si tu lis un char, utilise un char.
Marsh Posté le 22-10-2007 à 17:07:27
Ca y est je viens de comprendre. C'est en utilisant char et en voyant que ça fonctionnait comme ça que j'ai compris. En fait fread modifie 1 seul octet à partir de l'adresse contenu dans le 1er argument.
En fait sur mon pc j'ai tmp qui est sur 2 octets:
Programme Valeur des octets dans tmp
int tmp; 0x33 0x56 (valeurs quelconques)
fread(&tmp,1,1,fichier); 0x42 0x56 (1seul octet modifié)
Je pensais que le 2ème argument de fread (ici égal à 1) indiquait seulement le nbre d'octet à lire dans "fichier". La valeur contenue dans l'octet était alors assigné à l'élément pointé par le 1er argument (&tmp) quel que soit le nombre d'octet. Je croyais bètement qu'il devinait que tmp représentait 2 octets et qu'il inscrivait 66 en prenant en compte qu'il fallait qu'il modifie les deux octets.
Alors que tout ce qu'il sait ici c'est l'adresse de l'emplacement où il doit modifier x octets.
Edit:
Taz a écrit : Stockage != lecture. Même remarque que précédemment. man fread. Là tu lis un byte qui écrit partiellement un int. C'est mauvais. Si tu lis un char, utilise un char. |
Ah voilà j'aurai vu ça avant j'aurais plus vite compris, merci. C'est justement ce que je disais je croyais que le 2ème argument indiquait seulement le nbre d'octet à lire et non pas à écrire.
Merci de votre aide
Marsh Posté le 22-10-2007 à 17:11:56
Il faut avouer que la doc que j'avais porte à confusion: http://www.cplusplus.com/reference [...] fread.html
Size in bytes of each element to be read.
Marsh Posté le 22-10-2007 à 17:12:05
ReplyMarsh Posté le 22-10-2007 à 17:14:11
matafan a écrit : Bravo |
Dans une doc en pdf (pas de titre) ils disent que sur un PC c'est 16 bits comme le short.
Ah mais PC ne veux pas obligatoirement dire Windows c'est vrai.
Edit: sizeof(int) me sort 4, donc tu as raison
C'est vraiment intéressant le c pour ça, on découvre des trucs.
Marsh Posté le 22-10-2007 à 17:18:01
En fait, la norme garantie juste que la taille minimum d'un int c'est 16 bits.
Mais après, ça dépend du système. Et clairement en ce moment c'est plutôt 32 bits... quand ce n'est pas 64.
Marsh Posté le 22-10-2007 à 17:23:41
ngkreator a écrit : Je pensais que le 2ème argument de fread (ici égal à 1) indiquait seulement le nbre d'octet à lire dans "fichier". |
Le truc c'est de ne pas penser, et se référer à la documentation.
The function fread() reads nmemb objects, each size bytes long, from the stream pointed to by stream, storing them at the location given by ptr. |
Usage simple:
Code :
|
Marsh Posté le 22-10-2007 à 17:23:48
Ok merci pour la précision.
Sinon j'ai compris mon erreur, mais je ne comprends pas pourquoi ma fonction fonctionnait dans un cas mais pas dans l'autre:
Celle là ne fonctionnait pas:
Code :
|
Celle là si:
Code :
|
Et dans le premier cas pourquoi ça ne marchais pas quand le nombre de pointeurs dans ma structure nouvo_type était supérieur à 2?
Marsh Posté le 22-10-2007 à 17:28:32
bah parce que tmp est pas initialisé, et si fread échoue ou ne lis pas le bon nombre de données (ton cas, tu lis 1 au lieu de sizeof(int)), et bah t'as de la soupe dans tmp, écrasée partiellement par tes données.
Marsh Posté le 22-10-2007 à 17:35:51
Taz a écrit : Le truc c'est de ne pas penser, et se référer à la documentation.
|
Le nom de ta doc? J'ai suivi la mienne sans réfléchir etdu coup je l'ai cru bètement.
Taz a écrit : bah parce que tmp est pas initialisé, et si fread échoue ou ne lis pas le bon nombre de données (ton cas, tu lis 1 au lieu de sizeof(int)), et bah t'as de la soupe dans tmp, écrasée partiellement par tes données. |
Oui en fait je me suis mal exprimé. J'ai compris pourquoi ça marchait pas, ok.
Mais il y a deux fonctions: une qui ne marche pas, normal, mais il y en a une autre qui fonctionne alors qu'elle ne devrait pas.
2ème point, dans celle qui ne marche pas, il se trouve qu'elle fonctionne si le nombre de pointeur est infèrieur à 3.
Marsh Posté le 22-10-2007 à 17:42:14
ngkreator a écrit : Celle là ne fonctionnait pas:
|
Euh, tu as remarqué que tu lisais (mal) dans la variable tmp, mais que tu retournais la variable data (non initialisée) ?
Marsh Posté le 22-10-2007 à 17:47:27
tpierron a écrit : |
Oui, mais c'est une fonction fictive pour simplifier la présentation. J'allais pas vous noyer dans des trucs inutiles. Ma vraie fonction avait cette forme:
Code :
|
On voit le printf qui m'a servit à voir que c'était à ce fread que j'avais fait une connerie.
Marsh Posté le 22-10-2007 à 17:50:24
tous ces fread/fseek/malloc sans controller le retour, ça peut faire boom sans que tu t'en rendes compte.
Et ces malloc(<taille fixe/statique/connu à la compilation> ) dégage-les (sauf si tu comptres faire du realloc ensuite).
header=malloc(sizeof(int)*10);
-> int header[10];
Halte au nombre magique. Utilise sizeof et pas 4. Tu veux donner du sens, et bien "sizeof(int)" voire "sizeof largueur" ça ça a du sens. 4 non.
Marsh Posté le 22-10-2007 à 17:58:35
Taz a écrit : tous ces fread/fseek/malloc sans controller le retour, ça peut faire boom sans que tu t'en rendes compte. |
Attention cette fonction est le résultats de moultes suppressions (nottamment les controles des fread/fseek/malloc) pour essayer d'alléger aux max la fonction. Cette fonction est pourrie et m'a juste servi à trouver l'erreur. La variable tmp n'a rien à faire là (juste pour simplifier les test), elle remplace un tableau qui devait me servir dans la structure. Et encore j'ai enlevé les commentaires qui m'avait permit d'isoler le fread.
Par contre je prends toutes tes remarques car dans ma vrai fonction j'avais utilisé des malloc pour rien aussi et les sizeof également.
Marsh Posté le 22-10-2007 à 18:09:48
ngkreator a écrit :
|
Ce code est horriblement pas portable... Tu fais l'hypothèse qu'un int fait 4 octets, ce qui est faux (la norme dit, en d'autres termes, 'au moins 2 octets'). De plus, il ne tient pas compte de l'endianess...
C'est pas comme ça qu'on fait. On lit octet par octet avec fgetc() et on charge comme ll faut les octets dans les variables à coup de décalage dans le bon sens. La convention réseau/fichiers est MSB en tête (sauf formats Microsoft à la gomme, genre BMP ou WAV).
Marsh Posté le 22-10-2007 à 18:22:35
Emmanuel Delahaye a écrit : |
Merci
Je viens de découvrir ce qu'est l'endianess, je m'étais d'ailleur posé la question de où se situaient les octets de poids fort (si on peut appeler ça comme ça?) quand une donnée était inscrite sur plusieurs octet.
Grâce à toutes ces remarques (posts précédents inclus) je vais pouvoir faire un truc déjà plus potable
Marsh Posté le 22-10-2007 à 18:35:14
En fait, dans ce cas, il a raison d'utiliser 4 et pas sizeof(int). Il lit un format de fichier complètement figé depuis 15 ans au moins et qui ne changera certainement plus (au risque de péter qqs milliers d'applications, ce que Microsoft ne prendra jamais le risque de faire). Je changerais plutôt les variables int en uint32_t (déclarés dans stdint.h).
Sinon GDI+, dispose de tout un tas de fonction pour lire des bitmaps direct en mémoire. Bon, il faut coder sous Windows.
Marsh Posté le 22-10-2007 à 18:43:40
tpierron a écrit : En fait, dans ce cas, il a raison d'utiliser 4 et pas sizeof(int). Il lit un format de fichier complètement figé depuis 15 ans au moins et qui ne changera certainement plus (au risque de péter qqs milliers d'applications, ce que Microsoft ne prendra jamais le risque de faire). Je changerais plutôt les variables int en uint32_t (déclarés dans stdint.h). |
Ah mais le but c'est de m'amuser et d'arriver à modifier des bmp sans bibliothèques qui vont me fournir des fonctions déjà toutes faites.
Avant ce week end je savais pas que les images bmp était de simples fichiers binaires qu'on pouvait modifier octet par octet . Je veux vraiment partir de la base et voir comment ça fonctionne.
Un jour je m'essayerai au jpeg avec fourrier
En fait c'est parti du prof de méca en vibration qui nous explique fourrier, puis le fait qu'on l'utilise dans le jpeg et moi qui me dit mais ça doit être intéressant tout ça
Marsh Posté le 24-10-2007 à 19:00:47
J'ai avancé sur ma fonction me permettant de charger un fichier dans une structure. Elle prend un fichier en paramètre, renvoie un pointeur sur une structure.
J'ai initialisé une struture dans la fonction pour renvoyer son adresse par la suite. Je pensais que ça n'allais pas marcher puisque que tout variable interne à une fonction ou un bloc était invisible à l'extérieur. Invisible mais pas "détruit" apparemment puisqu'on peut y accéder par son adresse.
L'avantage c'est que j'ai les tableaux qui contienne l'en tête du fichier bmp dans la structure ont déjà leur espace mémoire.
J'ai hésité pour la disposition des if,else et return en cas d'erreur. Ca pose problème de faire plusieurs return en plein milieu de la fonction? J'ai essayé de ne faire que 2 return (1 pour renvoyer la structure l'autre un pointeul NULL en cas d'erreur) avec une cascade if,else assez imbuvable.
J'ai pas jugé utile de tester les fgets, en considérant que si la fin du fichier n'est pas atteinte (vérifié par feof) le programme devrait s'en sortir pour lire un octet.
La structure
Code :
|
La fonction
Code :
|
Pour lire la valeur de plusieur octet dans le bon sens je vais remplacer le for suivant par une fonction:
Code :
|
A remplacer par (en considérant que dans un bmp l'octet de poids faible est placé en 1er):
Code :
|
J'ai des problèmes avec cette fonction, mais c'est normal je trouverai le problème.
Marsh Posté le 24-10-2007 à 21:46:43
Erreur, il ne faut jamais retourner une variable locale à une fonction, elle n'existe que dans la fonction et la mémoire est libérée à la sortie de la fonction. Si tu arrives à lire en passant par l'adresse, c'est que cette mémoire n'a pas encore été écrasée au moment où tu la lis.
Fais plutot un truc du style :
Code :
|
Marsh Posté le 24-10-2007 à 22:23:36
xilebo a écrit : Erreur, il ne faut jamais retourner une variable locale à une fonction, elle n'existe que dans la fonction et la mémoire est libérée à la sortie de la fonction. Si tu arrives à lire en passant par l'adresse, c'est que cette mémoire n'a pas encore été écrasée au moment où tu la lis.
|
En fait à quoi correspond la taille de struct_bmp puisqu'elle n'a pas de taille définie? Il y a un pointeur de pointeur (**data) à l'intérieur.
Marsh Posté le 25-10-2007 à 09:01:25
sa taille est parfaitement définie :
unsigned char header[10] fait 10 octets.
unsigned char info_header[40] fait 40 octets.
unsigned char **data est un pointeur , il fait donc la taille d'une adresse sur ta machine (généralement 4 octets).
Marsh Posté le 21-10-2007 à 10:09:36
Bonjour à tous, j'ai récemment découvert que les fichiers bmp était facilement modifiables grâce à ce site: http://www.wotsit.org/ et notamment cette page http://www.fortunecity.com/skyscra [...] ffrmt.html
J'ai essayer avec un éditeur hexadécimal de voir si ça correspondait et effectivement oui (heureusement :D )
Du coup je me suis lancé avec fread et fwrite pour modifier des octets et ça a marché. Je me suis donc amusé à récupérer la taille, la résolution puis à modifier des pixels jusqu'a créer une fonction "négatif" qui inverse toutes les couleurs de l'image.
Mais seulement voilà, je découvre les erreurs de "linkage", je ne sais pas si le terme est juste. Apparemment le linker ne trouve pas un truc qui devrait se trouver là où il cherche.
Voilà ce que codeblocks me donne:
Switching to target: default
Linking console executable: E:\Documents\Programmes\avi\avi.exe
.objs\bmp.o:bmp.c:(.text+0xf5): undefined reference to `seek'
collect2: ld returned 1 exit status
Process terminated with status 1 (0 minutes, 0 seconds)
0 errors, 0 warnings
Apparemment l'erreur vient du fichier bmp.c (logique elle est apparue après de modif dans des fonctions de ce fichier). Mais la compilation à l'air d'avoir été faite (bmp.o) mais c'est au moment de la création des liens que ça bloque. Il faudrait donc configurer le linker? Bizzare étant donné que je n'utilise rien de spécial comme bibliothèque.
J'ai 3 fichiers dans mon projet: main.c, bmp.h et bmp.c
J'ai inclu stdio.h et stdlib.h
Voilà mes fichiers:
main.c
bmp.h
bmp.c
Merci pour votre aide, je continue à chercher...
Message édité par ngkreator le 22-10-2007 à 15:19:51