Aller au menu - Aller au contenu

Profil du membre : SofEvans

Informations générales | Communiquer | Activité sur le site | En savoir plus | Signature | Biographie

Informations générales

"Cours !!! Il a des grenades !!"
Avatar
  • Pseudo : SofEvans
  • Groupe : Membres
  • Date d'inscription : Le 22/01/2010
  • Dernière visite : Il y a 1h50
Hors ligne SofEvans est hors ligne
 

Communiquer


Voir les informations masquées

Activité sur le site

Nombre de messages : 4191
Nombre de tutoriels : 0
Nombre de news : 0

Profil

  • Date de naissance : Le 10/02/1989
  • Age : 23 ans
  • Ses études : ETNA
  • Son travail : Etudiant
  • Ses passions : Airsoft, vous y croyez ?

Signature

Petit truc et astuces pour programmer différemment : voir biographie
Bio de uknow : A lire pour ceux qui sont curieux

Mon pseudo c'est SofEvans et pas SoftEvans.
Ca me fait bizarre que tout le monde me prenne pour un logiciel ...
D'ailleurs, j'ai ajouté deux listes à ma bio

 

Biographie

Je tiens à remercier grandement tous ceux qui ont corrigé ma biographie.
Merci pour leur travail titanesque, il faut dire que je suis une bille en orthographe (mais ça n'excuse rien).
Encore une fois, un énorme merci pour ceux qui vont pouvoir désormais lire cette page sans perdre la vue.

Correcteur (dans l'ordre)
L'Ombre Blanche
omay
Piwakk



Avant-propos :

N'hésitez pas à me contacter si un aspect vous semble trop obscur ou si vous avez des questions.
Bonne lecture.



Bonjour à toutes et à tous.

Si vous lisez ma biographie, c'est très probablement que vous avez posté un problème sur le Forum C et que dans une réponse il y a un lien vers cette biographie. Il se peut aussi que ce soit moi qui vous y aie dirigés de manière un peu brutale et non conviviale.

Disclaimer : La suite de l'intro ne vous concerne pas à moins que je vous l'aie dit explicitement.
Pas la peine de prendre la tangente, et si vous vous reconnaissez dedans, venez pas râler.

Secret (cliquez pour afficher)
Avant de continuer, je voudrais vous faire part d'une réflexion qui a dû s'imposer à moi.
Lors de mon activité sur le Forum C du SiteDuZéro, j'ai remarqué que beaucoup de personne demandant de l'aide font preuve d'une grande immaturité et d'un mépris aussi dissimulé qu'une bouse de vache à l'entrée de votre maison.
Le problème est que ce comportement n'est pas isolé du tout et tend à se généraliser. C'est d'autant plus regrettable que cela décourage et dégoûte des habitués du Forum C qui donnent beaucoup d'eux-mêmes.

Alors d'où vient ce comportement ?
On pourrait attribuer ça au fait que ces posteurs sont des enfants effectivement immatures, mais cela n'explique pas tout.
Comment ces personnes peuvent-ils se monter la tête au point de nous cracher à la figure quand on veut les aider ?
Cela m'amène à remarquer que le tutoriel de m@téo21 n'y est pas pour rien.
En effet, lors de sa lecture, on ressent une sorte de promesse.
"Si vous voulez programmer en C, lisez ceci et vous saurez le faire facilement !".
C'est le message implicite de m@téo21, je l'ai senti comme cela, et de mes discussions avec d'autres membres, il en est de même pour eux.

Et en y réfléchissant, c'est là le nœud du problème.
C'est donc dans cette mentalité que la plupart de ceux qui demandent de l'aide viennent sur le Forum.
Il convient de rectifier cet effet pervers.

On ne peut pas nier que le tutoriel de m@téo21 permet de rapidement prendre conscience de plusieurs concepts du langage C.
Cependant, si la pensée que vous savez programmer en C vous a effleurés, vous pouvez tout de suite vous l'ôter de la tête.
Le langage C est un langage. Pensez-vous vraiment maîtriser un tant soit peu un langage ?
Regardez vos posts, ils sont dans le langage Français qui est votre langue maternelle pour la plupart, c'est-à-dire que c'est un langage que vous pratiquez depuis votre enfance !
Si on lit vos posts, ils sont, tout comme les miens, blindés de fautes d'orthographe ! Pensez-vous vraiment maîtriser le langage Français ?
En conclusion, soyez humble !

Pour commencer à avoir une sensation de maîtrise sur le langage C, il faut posséder plusieurs choses :

- une curiosité presque insatiable ;
- une rigueur à la limite de la paranoïa ;
- une bonne mémoire ;
- une grande autonomie ;
- et surtout, des années de pratique.

Bien sûr, je grossis le tableau. Ce n'est pas avec juste ces cinq points que vous pourrez maîtriser le langage C ou tout autre langage. Même ces points peuvent être mis en défaut. Cependant, ces points sont pour ma part indispensables à toute personne qui désire vraiment maîtriser une grande partie du langage C.
Bien sûr, il est possible de rester à un niveau humble de maîtrise et de pouvoir faire des programmes qui valent le détour.
En ce moment, je pense à Jay81 et à sa création "Wiwi's Adventures".
Comme quoi, on peut ne pas approfondir tous les aspects et faire de belles choses.

En bref, sachez avant tout être autonome !
Trop de zéros ne prennent pas la peine de chercher par eux-mêmes.
C'est ainsi qu'on voit fleurir des centaines de posts complètement inutiles.

"Bonjour, j'ai un probleme, mon IDE me renvoit
error: assignment discards qualifiers from pointer target type"

Il aurait suffit de faire une petite recherche Google avec exactement cette phrase pour avoir, à défaut de la réponse exacte, un très bon aperçu de ce qui a causé le problème.
La conclusion de ce long pavé, c'est que même si vous êtes débutant, même si le confort du tutoriel de m@téo21 vous rassure, sachez rassembler autant d'informations que possible par vous-mêmes. Si vous n'êtes pas capables de faire ça, ou pire, si vous n'en avez pas l'envie, n'espérez pas pouvoir faire de gros programmes.

Les moyens mis à votre disposition sont nombreux, variés et riches en informations !
Le premier, c'est évidemment le moteur de recherche, que ce soit Google, Yahoo ou autre.
Vous avez aussi des FAQ. Ce sont des endroits où les questions les plus récurrentes sur le forum sont résolues. Autant dire qu'il est vital de l'avoir lue au moins une fois !
Il y a aussi d'autres tutoriels, certes moins conviviaux que ceux de m@téo21, mais riches en enseignements. Je pense notamment à ceux de developpez.com.
Il y a aussi les très austères DOC, dont la plus connue est le "man".
Si vous y réfléchissez, même l'éponge que vous achetez au supermarché possède un mode d'emploi (plus exactement : conseil d'utilisation). Si un objet aussi simple possède un mode d'emploi, vous vous imaginez bien que la librairie C qui regroupe toutes les fonctions de base d'un programme doit avoir un mode d'emploi aussi !
Ce mode d'emploi s'appelle "man", et il est très... peu convivial. Il est en anglais, même s'il est possible de l'avoir en français.


Voici donc des liens que vous pourrez exploiter.

La FAQ C du SiteDuZéro
La FAQ C de Developpez

Prenez la peine de les lire, ne serait-ce qu'une fois.
Croyez-moi, ça en vaut le coup (ne serait-ce que pour un petit rafraîchissement de mémoire).

Comme le dit si bien notre ami Adroneus :

Citation : Une des signatures Adroneus

Referez vous a la FAQ et la FAQ des bibliotheques tierces
Verifiez toujours les fonctions standard que vous utilisez, Read The Fucking Manual
Faites des recherches
Referez vous a d'autres forums : c.l.c, developpez
Exercez vous sur ce site, sur france ioi, sur Prologin, sur project Euler





Je me permets de citer ici la Bio de nepser :
Secret (cliquez pour afficher)

Citation : Bio nepser


Mon compilateur me dit undefined reference ...


Cela signifie que le compilateur ne trouve pas la définition de la fonction en question (le code entre les {})

Voici les raisons possibles:

  • Vous vous êtes tout simplement planté dans le nom de la fonction, relisez bien
  • Vous avez mal ajouté le fichier contenant la fonction à votre projet. Essayez de l'enlever puis de le remettre en cochant bien les cases "debug" et "release" pour qu'il soit compilé
  • Vous ne compilez dans le langage qu'il faut: cela arrive lorsque votre fichier porte l'extension .cpp alors que le reste du code est en .c par exemple. Dans ce cas, renommez TOUS vos fichiers .cpp en .c
  • Vous compilez en ligne de commande, donc vous n'avez pas compilé/linké le fichier contenant la foncton, relisez votre ligne de commande/makefile


Si la fonction en question n'est pas de vous, c'est que vous n'avez pas ou mal linké les bibliothèques nécessaires à l'utilisation de la fonction. (pensez à -lm si vous utilisez une fonction mathématique par exemple)

Note: Si vous êtes sous Code::Blocks, faites un click droit sur chaque fichier source, aller dans les propriétés puis dans l'onglet avancé, vérifiez ensuite que la variable compilateur est CC et non pas CPP.
Si vous êtes sous Visual C++, allez aussi dans les proriétés de vos fichiers sources, dans C/C++ avancé, vérifier que vous "compiler en tant que C" et pas C++.

Exemple courrant:
undefined reference to `_WinMain@16'
Cette erreur peut arriver lorsque vous avec mal configuré l'installation de la SDL.
Dans les options du linker (Build Options/Linker Settings) vérifiez que vous avez mis dans link libraries:
mingw32
SDLmain
SDL
OU dans other link options
-lmingw32
-lSDLmain
-lSDL


J'ai des centaines de fois "unhandled value ..."



Cela signifie que vous ne gérez pas tous les cas possibles dans un switch, il faut donc ajouter un default à la fin de votre switch.

Exemple:
Code : C
1
2
3
4
5
6
7
8
switch(event.type)
{
    case SDL_KEYDOWN:
        //...
    break;
    default:  //dans tous les autres cas
        ; //je ne fais rien
}




____________________________________________________________________________________________________________________________



Voici une liste des erreurs et maladresses rencontrées régulièrement sur le forum C.
Chacun des cas suivants aura bien évidemment une solution.


J'ai d'incompréhensibles bugs


Secret (cliquez pour afficher)
Il se peut que des fois, malgré tout le soin que vous ayez pu apporter, vous soyez victime de bugs très étranges.
Par bug, j'entends ici "erreur".
La première des choses à vérifier c'est : est-ce que vous compilez réellement en C ?
(Je vous rappelle que ce texte s'adresse au forum C.)

Pour en avoir le cœur net, il n'y a pas trente-six moyens.
Rajoutez ce morceau de code en tout début de main.c, c'est-à-dire en ligne 1.


Code : C
1
2
3
#ifdef __cplusplus
#error Vous utilisez un compilateur C++ pour compiler un code C.
#endif



Ainsi, si vous compilez en C++, cela déclenchera une erreur.
Vous verrez ce message :

"error : Usage d'un compilateur C++ pour compiler un code C."

Si vous ne voyez pas ce message, c'est que vous compilez en C.

Voici une liste non exhaustive d'erreurs pouvant provenir d'une compilation C++.
* Lors d'un malloc, vous n'avez pas casté et cela vous provoque une erreur "invalid conversion from (le type)* to void*".
* Les includes semblent parfaits, mais visiblement, cela ne veut pas compiler.



J'utilise la SDL, et le blit bug


Secret (cliquez pour afficher)
Oui, je sais, le mot bug revient très souvent. Mais en réalité, il n'y en a pas.
C'est très certainement de votre faute si votre programme échoue.

Voici la plus grande des maladresses des débutants C.
(Enfin, on va plutôt dire que si cette maladresse n'était pas commise, beaucoup de threads ne seraient pas sur le forum.)

Un exemple :

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdlib.h>
#include <stdio.h>
#include <SDL/SDL.h> /* Merci Qubs */


int main (int argc, char *argv[])
{
    /* Initialisation SDL */
    SDL_Init(SDL_INIT_VIDEO);


    SDL_Surface *ecran = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE | SDL_DOUBLEBUF );
    SDL_Surface *image = SDL_LoadBMP("ma super image.bmp");

    SDL_BlitSurface (image, NULL, ecran, NULL);
    SDL_Flip(ecran);

    /* On fait une pause de 2 secondes afin d'admirer notre super image */
    SDL_Delay (2000);

    /* Il ne faut pas oublier de libérer les surfaces (merci thiblt04) */
    SDL_FreeSurface (image);

    SDL_Quit();

    return 0;

}


Ce code paraît tout à fait juste, les valeurs sont correctes au premier abord.
Pourtant, c'est une véritable bombe à retardement que vous avez là.

En effet, en regardant uniquement le code, pouvez-vous me dire si l'image est correctement chargée ?

Ne me dites pas "oui", dans l'état actuel des choses, c'est impossible à savoir.
"Quelle importance, l'image s'affiche !" me diriez-vous.
Certes, mais considérez le cas où pour X ou Y raisons, cela échoue.
C'est tout à fait probable. Voici une petite liste de raisons :

* Le chemin vers le fichier est erroné.
* L'extension de l'image n'est pas la bonne.
* Vous n'avez pas les droits nécessaires pour accéder au fichier image.
* Il vous manque une dll dans votre projet.
* ...

Pire encore, on ne peut pas savoir si la SDL (qui est quand même à la base de votre programme) s'est correctement initialisée.
On ne sait pas non plus si l'écran a été créé, et c'est quand même LA surface que l'utilisateur va regarder.
En bref, c'est pas très consciencieux tout ça.

Que faire dans ce cas ?

Il faut tester le retour des fonctions !
Mais attention, pas de toutes les fonctions (on va pas s'amuser à regarder le retour de SDL_BlitSurface pour le moment).

Ce qu'il faut faire, c'est prendre en compte les erreurs qui auront un réel impact sur votre programme.
Et celles qui ont le plus d'impact, c'est celles qui font de l'allocation dynamique.
Si si, il y a de l'allocation dynamique en SDL.

Prenons la fonction SDL_LoadBMP. Regardons son retour, on voit
SDL_Surface*
La fonction retourne un pointeur vers une SDL_Surface, très certainement alloué.

Vous n'êtes pas sans ignorer LA règle d'or au sujet de l'allocation dynamique qui est :

1 malloc = 1 free

Vous saviez pas ? Ben maintenant si.
Pour les plus rapides, ceux qui se sont aperçus que SDL_LoadBMP équivaut à un malloc, vous vous
serez rendus compte qu'il manque le free (puisque 1 malloc = 1 free).
Pas de panique, tout est pris en compte, puisqu'il existe la fonction SDL_FreeSurface.

Voici donc une mini-liste des fonctions qui doivent toujours être vérifiées en SDL :

* SDL_Init
* SDL_LoadBMP
* SDL_DisplayFormat
* SDL_DisplayFormatAlpha
* SDL_CreateRGBSurface (sur conseil de L'Ombre Blanche)

Si vous utilisez les "extensions" (image et TTF) :
* TTF_OpenFont
* IMG_Load

Et la liste ne s'arrête pas.

Alors, depuis tout à l'heure, je vous parle de tester le retour. Certes, mais avec quelle valeur ?
Cela, vous pouvez le deviner, mais ne jouez pas à cela : il existe un moyen sûr et imparable, la DOC.


Bien, nous savons quelles fonctions tester, nous savons comment les tester (grâce à la doc). Mais cela n'est pas encore suffisant !
Il nous manque encore quelque chose. Tester, c'est bien, mais c'est inutile si vous n'en affichez pas la cause !
Comment deviner si l'image n'est pas chargée parce que le chemin est faux ? Et si vous n'avez pas les droits nécessaires pour la charger ?

Bref, il faut afficher l'erreur.
Et ça tombe bien, car la SDL peut s'en charger (encore heureux). La fonction s'appelle SDL_GetError() et renvoie, sous forme de chaîne de
caractères, la DERNIERE erreur rencontrée.


Voici donc le code corrigé de tout à l'heure.

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <stdlib.h>
#include <stdio.h>
#include <SDL/SDL.h>


int main (int argc, char *argv[])
{
    /* Initialisation SDL */
    if (SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        fprintf (stderr, "Erreur lors du chargement de la SDL : %s\n", SDL_GetError());
        exit (EXIT_FAILURE);
    }

    /* Création de la surface de rendu vidéo */
    SDL_Surface *ecran = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE | SDL_DOUBLEBUF );
    if (ecran == NULL)
    {
        fprintf (stderr, "Erreur lors de la création de la fenêtre avec 'SDL_SetVideoMode' : %s\n", SDL_GetError());
        exit (EXIT_FAILURE);
    }


    SDL_Surface *image = SDL_LoadBMP("ma super image.bmp");
    if (image == NULL)
    {
        fprintf (stderr, "Erreur lors de l'initialisation de la variable 'image' avec la fonction 'LoadBMP'.\n");
        fprintf (stderr, "%s\n", SDL_GetError());
        exit (EXIT_FAILURE);
    }

    SDL_BlitSurface (image, NULL, ecran, NULL);
    SDL_Flip(ecran);

    /* On fait une pause de 2 secondes afin d'admirer notre super image */
    SDL_Delay (2000);

    SDL_FreeSurface (image);

    SDL_Quit();

    return EXIT_SUCCESS;

}


Alors, oui, je sais ce que vous pensez.
Ça rajoute des lignes, c'est chiant, c'est inutile parce que moi je suis un big boss et je sais charger une image, ça échoue pas,
bla bla bla.
Bref, pour ceux que ce petit discours a atteints et qui ont pris conscience de l'importance de bien vérifier ce que fait le
programme (à quoi ça sert de continuer à construire la tour de Pise ?), vous vous demandez sûrement comment appliquer tout ça
autre part que sur la SDL.

Le comportement est similaire.
Prenons le cas de la libC et de la fameuse fonction malloc.
Pour savoir comment tester le retour, il faut la doc de la libC, elle s'appelle "man".
La fonction qui permet d'afficher l'erreur, c'est "perror()".
Elle a un fonctionnement un peu particulier, mais grâce au "man", vous saurez vous dépatouiller.


NB : Personnellement, quand je teste un pointeur, je mets toujours NULL. Certaines personnes codent différemment.
Vous verrez peut-être cette syntaxe-ci :

Code : C
1
2
3
4
5
6
7
SDL_Surface *image = SDL_LoadBMP("ma super image.bmp");
    if (!image)
    {
        fprintf (stderr, "Erreur lors de l'initialisation de la variable 'image' avec la fonction 'LoadBMP'\n");
        fprintf (stderr, "%s\n", SDL_GetError());
        exit (EXIT_FAILURE);
    }


Je ne m'avancerai à rien, mais selon ces personnes, c'est totalement valide.


En bref et en conclusion, avant de dire que votre blit ne marche pas et que SDL_BlitSurface est buggée, vérifiez la validité de vos allocations.


Petit cadeau bonus :
Vérifier le retour des SDL_LoadBMP ou IMG_Load, c'est chiant, nous sommes d'accord. Mais si vous lisez ceci, c'est que vous
vous dites que finalement, ça serait bien utile tout ça.
Voici une fonction que j'ai faite afin de ne pas réécrire à chaque fois le test de vérif et aussi pour profiter de l'optimisation de SDL_DisplayFormat[Alpha].

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
SDL_Surface* ChargerImage(char* cheminFichier)
{
    char nouveauChemin [100];
    sprintf (nouveauChemin, "ressource/Images/%s", cheminFichier);


    /* Ouverture de l'image et vérification */
    SDL_Surface* imageFichier = IMG_Load (nouveauChemin);
    if (imageFichier == NULL)
    {
        fprintf(stderr, "Erreur lors de l'appel à 'IMG_Load' dans la fonction 'ChargerImage' du fichier 'votreFichier.c'.\n");
        fprintf(stderr, "%s\n", SDL_GetError());
        exit (EXIT_FAILURE);
    }

    /* On active la transparence sur COULEUR_TRANSPARENCE si la transparence n'est pas déjà fixée */
    /** Cette fonction est à appeler avant SDL_DisplayFormat[Alpha] car selon la DOC :
        If you want to take advantage of hardware colorkey or alpha blit acceleration, you should set the 
        colorkey and alpha value before calling this function
        Merci Psykie ;) **/
    if (!(imageFichier->flags & SDL_SRCCOLORKEY))
        if (SDL_SetColorKey(imageFichier, SDL_SRCCOLORKEY, SDL_MapRGB(SDL_GetVideoSurface()->format, 255, 0, 255)) == -1)
        {
            fprintf(stderr, "Erreur lors de l'appel à 'SDL_ColorKey' dans la fonction 'ChargerImage'");
            fprintf(stderr, "du fichier 'votreFichier.c'.\n");
            fprintf(stderr, "%s\n", SDL_GetError());
            exit (EXIT_FAILURE);
        }



    /* On convertit l'image pour l'optimiser et on vérifie
       On utilise la bonne fonction en fonction qu'il y a
       ou non de la transparence alpha */
    SDL_Surface* optimiser = NULL;

    if (imageFichier->flags & SDL_SRCALPHA)
        optimiser = SDL_DisplayFormatAlpha(imageFichier);
    else
        optimiser = SDL_DisplayFormat(imageFichier);

    if (optimiser == NULL)
    {
        fprintf(stderr, "Erreur lors de l'appel à 'SDL_DisplayFormat' ou 'SDL_DisplayFormatAlpha'");
        fprintf(stderr, "dans la fonction 'ChargerImage' du fichier 'votreFichier.c'.\n");
        fprintf(stderr, "%s\n", SDL_GetError());
        exit (EXIT_FAILURE);
    }

    /* On n'a plus besoin de imageFichier */
    SDL_FreeSurface (imageFichier);

    return optimiser;

}


J'explique rapidement deux trois choses :
Code : C
1
2
char nouveauChemin [100];
sprintf (nouveauChemin, "ressource/Images/%s", cheminFichier);

J'ai pris l'habitude de ranger mes images dans un dossier, ce dossier étant lui-même dans un dossier "ressource" (parmi les dossiers "Font", "Sons", ...).
Donc, si je dois rentrer le path d'une image, je devrais tout le temps écrire "ressource/images/monImage.exemple".
Y'a pas à dire, au bout d'un moment, c'est pénible.
Donc, je ne passe que le path de l'image NON pas par rapport au dossier du projet, mais par rapport au dossier des images.
Ainsi, je n'ai qu'à écrire "monImage.exemple" et la fonction va chercher cela dans "ressource/images/monImage.exemple"
(encore une astuce de feignasse).

Dernière chose, ceci :
Code : C
1
2
3
4
5
6
7
8
9
/* On active la transparence sur COULEUR_TRANSPARENCE si la transparence n'est pas déjà fixée */
    if (!(imageFichier->flags & SDL_SRCCOLORKEY)) /* merci qnope pour le coup d'oeil */
        if (SDL_SetColorKey(optimiser, SDL_SRCCOLORKEY, SDL_MapRGB(SDL_GetVideoSurface()->format, 255, 0, 255)) == -1)
        {
            fprintf(stderr, "Erreur lors de l'appel à 'SDL_ColorKey' dans la fonction 'ChargerImage'");
            fprintf(stderr, " du fichier 'votreFichier.c'.\n");
            fprintf(stderr, "%s\n", SDL_GetError());
            exit (EXIT_FAILURE);
        }

J'ai défini une couleur de transparence pour toutes mes images, c'est (255, 0, 255). De une, rien ne vous empêche d'en choisir une
autre ; de deux : mis comme cela, le SDL_SetColorKey est appelé pour chaque image, ce qui peut se révéler problématique.

Vous avez une base, à vous de l'adapter à vos besoins.



Je comprends pas, mon code ne marche pas mais j'ai 0 warning et 0 erreur


Secret (cliquez pour afficher)
Ce chapitre est en cours de construction, mais il a pour but de sensibiliser les personnes aux options
de compilation et d'en donner les options minimum.

Option minimum :
[-W] (Et non pas [-w] !!! J'insiste.)
[-Wall]

SI vous voulez que votre code soit compilable en C89/C90 :

[-W]
[-Wall]
[-ansi]
[-pedantic]



Disclaimer : Le code de retour pour SDL_LoadBMP/IMG_Load n'est pas fait, il a pour but de mieux expliquer la fonction ChargerImage précédente.
Bonne lecture.

Secret (cliquez pour afficher)
Dans ce chapitre, je considère que vous souhaitez vraiment contrôler les retours de fonctions afin d'écarter le plus possible de pistes lors d'une erreur, ou tout simplement pour avoir directement l'erreur.
Effectivement, imaginez le scénario suivant : vous avez enfin fini un jeu, et vous souhaiteriez que vos amis en soient les testeurs. Vous distribuez donc votre exécutable, et éventuellement les ressources telles que par exemple un fichier texte, une image, un son...
Impatient, votre ami exécute et ô cruelle surprise, le programme plante, voir même fait planter l'ordinateur.

Vous vous retrouvez donc face à un problème bien épineux, puisque si vous n'avez pas, dans votre code, géré un minimum les erreurs, vous n'aurez rien pour rectifier le problème. Comment savoir si le problème provient de l'ordinateur de votre ami ou de votre code ? Ou encore, si cela provient d'une ressource externe manquante, défectueuse ou pas à la bonne place ?
C'est à ce moment que vous devez imaginer toutes les possibilités, émettre toutes les hypothèses, faire tous les tests afin de trouver l'origine de ce si pénible problème. Cela peut prendre 5 minutes comme des jours, semaines, ou même des cheveux (certains en deviennent même chauve, c'est dire).

La meilleur situation serait un fichier créé par le programme qui vous dirait l'erreur, tâche à vous de la corriger. Et c'est exactement ce que nous allons faire !

Avant de continuer, je dois vous expliquer sur quel type de programmation je compte utiliser cette gestion d'erreur.
Il existe, par exemple, la programmation ''par contrat''. Très grossièrement, on pourrait dire que le programme s'engage à délivrer le bon résultat si l'utilisateur fournit correctement les informations. Il existe aussi des programmes qui ne doivent pas échouer, quelles qu'en soient les raisons.
Dans notre contexte, nous allons utiliser le type de programme dit ''manichéen'', c'est-à-dire que soit le programme fonctionne sans aucun problème, soit il s'arrête dès la première erreur.
Ainsi, si le programme plante, ce sera à la première erreur, ce qui nous assure de ne pas avoir une pléthore d'erreurs provoquées par la première, autrement dit de ne pas avoir d'effet boule de neige.

Quelles seront donc les fonctions à vérifier ? Quelle fonction peut vraiment influer sur le programme au point de le faire complètement planter ?

Pour ma part, j'identifie quatre catégories de fonctions à vérifier :
- Toutes les fonctions retournant des pointeurs.
- Toutes les fonctions chargeant des ressources, telles fichier texte, image...
- Toutes les fonctions communiquant avec un utilisateur.
- Les fonctions vraiment importantes.


Parmi celles de la librairie standard, les fonctions concernées sont donc :
- malloc : 1ère catégorie ;
- fopen : 1ère et 2ème catégorie ;
- fgets, gets, scanf... : 3ème catégorie ;
- bien d'autres encore, mais celles-ci sont les principales vues dans le tutoriel de m@téo21.

Parmi celles de la librairie SDL, nous avons :
- SDL_Init : 4ème catégorie ;
1ère et 2ème catégorie :
- SDL_LoadBMP ;
- SDL_SetVideoMode ;
- SDL_CreateRGBSurface.

Ensuite, nous avons les extensions de la SDL, telles que SDL_ttf, SDL_image :
- TTF_Init : 4éme catégorie ;
1ère et 2ème catégorie :
- TTF_OpenFont ;
- IMG_Load.

Bien évidemment, ces listes ne sont pas exhaustives, elles représentent juste la plupart des fonctions présentes dans le tutoriel de m@téo21 et sur le forum C du Site Du Zéro.

Nous allons ici décortiquer deux fonctions : malloc et SDL_LoadBMP/IMG_Load.

Dans un premier temps, organisons-nous. Notre travail sera dans un .h et un .c. Je vais les appeler VerifFonction.h et VerifFonction.c.

Commençons par malloc.
Le prototype de malloc est :

Code : C
1
void* malloc (size_t size);


Donc, notre prototype sera :

Code : C
1
void* my_malloc (size_t size);


Jusque-là, rien de bien choquant.
Voyons donc le corps de la fonction :

Code : C
1
2
3
4
void* my_malloc (size_t size)
{
    return malloc (size);
}


Si nous faisons ceci, alors cette fonction aura le même comportement que malloc. Or, nous voulons vérifier et valider le fait que le pointeur retourné ne soit pas NULL.

Code : C
1
2
3
4
5
6
7
8
9
void* my_malloc (size_t size)
{
    void* ptr = malloc (size);
    if (ptr == NULL)
    {
        exit(EXIT_FAILURE);
    }
    return ptr;
}


Voilà, nous venons de vérifier si le pointeur retourné par malloc était valide, s'il ne l'est pas, alors nous arrêtons le programme.
C'est un bon début, mais cette gestion comporte un gros problème : nous ne savons toujours pas pourquoi la fonction a échoué. Il faut pour cela utiliser la fonction perror. Cette fonction écrit dans stderr la dernière erreur rencontrée. Perror ne concerne que les fonctions de la librairie standard, et malloc en fait évidemment partie.

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
void* my_malloc (size_t size)
{
    void* ptr = malloc (size);
    if (ptr == NULL)
    {
        perror ("Erreur sur le malloc : ");
        exit(EXIT_FAILURE);
    }
    return ptr;
}


Cette fois-ci, nous avons la vérification et la cause !
Cependant, que se passe-t-il pour ce code ?

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include <stdio.h>
#include "VerifFonction.h"

int main (void)
{
    my_malloc (100000);
    my_malloc (10890000);
    my_malloc (1023450000);

    return EXIT_SUCCES;
}


Un de ces appels risque de planter, cela dépendra de l'ordinateur sur lequel sera exécuté le code.
Une solution serait, en plus de donner l'erreur via perror, d'informer la ligne et le fichier où l'appel a été effectué.
Heureusement, il existe des macros __LINE__ et __FILE__ pour nous donner ces informations.
Modifions donc notre fonction.

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
void* my_malloc (size_t size, char* nomFichier, int numeroLigne)
{
    void* ptr = malloc (size);
    if (ptr == NULL)
    {
        fprintf (stderr, "Erreur a la ligne %d du fichier %s\n", numeroLigne, nomFichier);
        perror ("Erreur sur le malloc : ");
        exit(EXIT_FAILURE);
    }
    return ptr;
}


Cela nous oblige à passer deux arguments en plus à chaque appel de malloc !

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include <stdlib.h>
#include "VerifFonction.h"

int main (void)
{
    my_malloc (100000, __FILE__, __LINE__);
    my_malloc (10890000, __FILE__, __LINE__);
    my_malloc (1023450000, __FILE__, __LINE__);

    return EXIT_SUCCES;
}


Ainsi, il n'y a plus de confusion possible. On connaît la ligne, le fichier, la fonction en cause et la cause du plantage.
Le seule problème restant est qu'il va falloir trouver tous vos malloc pour les transformer et passer deux arguments supplémentaires qui seront toujours les mêmes.

Heureusement, le langage C est un langage qui nous réserve des surprises.
Vous connaissez #define ?
Peut-être avez-vous entendu parler des macros ?

Et bien nous allons voir comment une macro peut considérablement nous faciliter la mise !!!
/** lien vers tuto de pouet_forever **/

Avant cela, récapitulons.

VerifFonction.h
Code : C
1
2
3
4
5
6
#ifndef VERIFFONCTION_H
#define VERIFFONCTION_H

void* my_malloc (size_t size, char* nomFichier, int numeroLigne);

#endif


VerifFonction.c
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#include <stdlib.h>
#include <stdio.h>

void* my_malloc (size_t size, char* nomFichier, int numeroLigne)
{
    void* ptr = malloc (size);
    if (ptr == NULL)
    {
        fprintf (stderr, "Erreur a la ligne %d du fichier %s\n", numeroLigne, nomFichier);
        perror ("Erreur sur le malloc : ");
        exit(EXIT_FAILURE);
    }
    return ptr;
}


main.c
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include <stdlib.h>
#include "VerifFonction.h"

int main (void)
{
    my_malloc (100000, __FILE__, __LINE__);
    my_malloc (10890000, __FILE__, __LINE__);
    my_malloc (1023450000, __FILE__, __LINE__);

    return EXIT_SUCCES;
}


Voici maintenant notre petite macro, à mettre dans VerifFonction.h.
Code : C
1
#define malloc(size) my_malloc(size, __LINE__, __FILE__)


Cette macro permet de remplacer chaque appel de malloc par un appel à notre malloc, soit my_malloc, tout en ajoutant __LINE__ et __FILE__.
Cela a deux avantages :
Nous avons réussi à passer automatiquement __LINE__ et __FILE__.
Il ne sert plus à rien de chercher tous les appels malloc pour les remplacer par my_malloc.

Vous pouvez donc garder vos habitudes en appelant malloc. Il suffit d'inclure "VerifFonction.h" en début de chaque .c pour qu'automatiquement, tous vos appels malloc soient valides et que le cas échéant, l'erreur soit correctement décrite pour vous permettre de la rectifier au plus vite.

Cependant, attention.
Vous ne devez pas inclure "VerifFonction.h" dans "VerifFonction.c".
En effet, si vous faites cela, alors l'appel à malloc dans my_malloc sera remplacé par un appel à my_malloc.
Autrement dit :


Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
void* my_malloc (size_t size, char* nomFichier, int numeroLigne)
{
    void* ptr = my_malloc (size, nomFichier, numeroLigne);
    if (ptr == NULL)
    {
        fprintf (stderr, "Erreur à la ligne %d du fichier %s\n", numeroLigne, nomFichier);
        perror ("Erreur sur le malloc : ");
        exit(EXIT_FAILURE);
    }
    return ptr;
}


On se retrouverait dans un cas de fonction récursive sans condition d'arrêt.



Voilà voilà, pour le moment, c'est pas mal, je continuerai à remplir petit à petit.
En espérant que ça vous ait aidé.


(Merci pour la petite correction, jolfo et lety)

_______________________________________________________________________________



Ma petite BlackList



Secret (cliquez pour afficher)
Au cours de mes croisades sur les forums, il m'est arrivé d'être tombé sur des sacrés énergumènes.
J'ai donc decidé de me faire ma petite blacklist.


ZeroSamy
Lui, c'est a cause d'un MP que je qualifierai de mythique.
Si j'arrive un jour a vous le mettre en image, je le ferai ^^

Symeon94
Ne pas savoir se débrouiller avec 5 codes totalement fonctionnels et écrit pour soi, c'est un foutage de gueule comme pas permi. Si vous ne comprenez pas un code fourni en exemple, dites le.
Une seule édition pour le moment

elmahdi
Il tient une sacré couche d'immaturité. Ce n'est pas parce que vous êtes tranquillement derrière votre PC qu'il faut craquer le slip.
1ere edition
2eme édition

elendile
Il y a un moment ou il faut arrêter.
1ere edition
2eme édition

mauricedelacour
Je ne dirai que une chose : omfgwtf ?
lien 1 : ...
edit : Topic mis à la corbeille et membre banni.

CydGy
Je n'ai même plus l'envie de décrire ce qui m'a poussé a le blacklister ...
Mais qu'arrive t-il aux helpers ???
Dieu, si tu existe, sauve nous ...
Il y a aussi un MP relativement mythique adressé à un autre membre que moi (heureusement) et pas mal d'autre topic dans le même genre.

(merci pour la petite correction DuaL)



_______________________________________________________________________________



Ma WhiteList




Au tour des gens vraiment intéressant, ceux qui quand ils parlent, on les écoute tout ouïe.
Alors bien sûr, il s'agit pas de faire un classement, c'est pourquoi ce sera par ordre alphabétique.

@che (sur conseil de _Fender_)
Adroneus
Arthurus
bluestorm
candide
Fvirtman
GurneyH
Marc Mongenet
Nathalya
Pouet_forever
Tosh
uknow
Taurre
joe78 (sur conseil de GurneyH)

Regardez les bios, souvent, on tombe sur des choses intéressantes.

Si vous ne faite pas partie de cette liste, c'est pas forcement que vous êtes nul ou pas intéressant, c'est
peut être parce que je vous connais pas tout simplement ou que je vous ai oublier.



_______________________________________________________________________________



Ma GreyList




ATTENTION, ceux-ci on fait L'ERREUR.
TREMBLEZ !


@che
Akio
Allenn
adri05
apprenti m@teo (evidemment, plus on leur dit de ne pas le faire, plus il le font ... ;) )
BigPuppy
bobinne13
bluestorm
C159
chiti
colbseton
DunCaN213
darkipod
deyy
elendile
epsilone
florent m (Ce n'est pas du troll, mais tu es quand même dedans :D )
Gloorian
GurneyH
hedi07
informaticienzero (même à l'oral, ça marche !)
kalalinuna
kev-le-noir
kimimsc
klunk
kottaro
Lucanae
link1991
luh3417 (et merci pour mon anniv ;) )
Marc Mongenet
Matrefeytontias
mazdalopitek
meteor2
natir
Pouet_forever
Poutrator
patatracq
perimgui
pingloveur
psykie
qnope
Vael
Voldeath
rayane314
roulemapoule
Tau_o
Tchoa
XX3
YozeFx
yannis51 (you are on da list)
WSJ

Une mention bien spécial à GurneyH, qui s'est vraiment bien amusé.
:pirate:


Secret (cliquez pour afficher)

Bon, si vous êtes dans la liste, stressez pas.
C'est juste un petit délire.
Cette liste recense toutes les personne m'ayant, volontairement ou non, appelé SofTEvans.
Ça en fait un sacré petit paquets, non ?



_______________________________________________________________________________






Depuis peu, je me suis aperçu que certaine personne me croyait pas lorsque je leur disait que sur
l'avatar, c'est moi-même.

Voici une petite preuve :


Image utilisateur


Bon, on voit totor en arriere plan avec son super sac discret, mais c'est pas grave ^^
Alors verifier vos allocation ! Ou je viens !! :pirate: