|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
C reparti ! C'est un dimanche pluvieux. Avachi devant votre écran de TV, qui ne fait que de couper vos pubs préférées par des séries débiles et ricaines, vous vous dites : "Tiens, si aujourd'hui je faisais un super programme méga-génial sur mon Amiga, avec tout plein de couleurs, de fenêtres et de gadgets et de...". Mais non ! Ça vous revient maintenant : vous ne savez pas programmer l'Amiga. Horreur, malheur ! Non, car tel le Zorro moyen, me voici accourir pour vous apporter un peu de lumière dans ce monde de brutes, où Billou a fermé la fenêtre... Attention : certains des listings de cet article peuvent planter. C'est pourquoi sauvegardez ce qui doit l'être avant de les exécuter ! Bon, c'est pour les besoins de l'initiation (elle a bon dos !) et uniquement dans cet article, les suivants ne poseront plus de problème... enfin normalement. ;-D Bien choisir son destrier : le compilo Le C a toujours été le langage de prédilection sur Amiga, c'est pourquoi un large choix de compilateurs s'offre à nous, qu'ils soient commerciaux ou dans le DP. Évidemment, chaque programmeur dira que le compilateur qu'il utilise est le meilleur, cependant, pour le néophyte qui n'est pas encore équipé, voici ceux que je préconise. Ce sont simplement ceux installés sur mes Amiga et dont je parlerai souvent dans mes articles. La Maserati, son excellence GCC Vous avez un Amiga accéléré (68020 ou plus), beaucoup de mémoire (au moins 8 Mo, 10 de préférence), de la place sur votre disque dur ou un lecteur de CD et vous savez ce qu'est un compilateur C : GCC est celui qu'il vous faut ! Pour le même prix, c'est-à-dire rien, il est gratuit, vous aurez droit au C, C++, Objective C, Ada et même Fortran. Conçu à l'origine pour Unix, vous le retrouverez comme compilateur natif des OS libres comme Linux, NetBSD, FreeBSD, etc. mais il existe aussi des portages sur des Unix commerciaux (HP-UX, AIX, Solaris, Digital Unix, etc. en fait, je ne crois pas qu'il existe un Unix récent sur lequel il n'ait pas été porté !). On le retrouve aussi sur Vax/VMS, BeOS, Mac, ST et même sur les Prehistorics Computers ! Outre le fait qu'il soit toujours plaisant d'utiliser le même compilateur d'une machine à l'autre, je lui trouve de nombreux avantages dont :
La deudoche, DICE Ce fut mon premier compilateur C sur Amiga. On préférera aller le chercher sur Aminet car la dernière archive en date contient la version professionnelle avec toutes les sources ! Elle comporte une GUI très bien faite et une interface ARexx complète. Relisez mes articles dans les anciens Amiga News et vous verrez qu'on peut même l'utiliser sur un simple Amiga 68000 muni d'1 Mo de mémoire et sans disque dur ! Comme avantage supplémentaire, la documentation est très bien foutue et comporte une initiation pour débutant, accompagnée d'exemples pour la création d'une bibliothèque, d'un périphérique logique. Il est aussi très bien intégré au système et gère pour vous l'ouverture automatique des bibliothèques, les arguments du Workbench... Bon, il contient aussi quelques bogues et l'exécutable n'est pas vraiment optimisé. Mention spéciale pour le Lattice (ou SAS C) Ce vieux compilateur, bien que plus vendu depuis un bail, continue à être soutenu par ses développeurs qui fournissent régulièrement des correctifs. Il possède un avantage indéniable : Commodore l'a utilisé pour développer le système, on trouve donc beaucoup d'exemples de programmation l'utilisant. Le premier programme Le voici, le voilà, la hantise de tous les débutants : le fameux "Hello World!". En voici le source :
On compile, et on l'exécute depuis un Shell : "Ça marche !". Décidément, on se moque vraiment de notre gueule ! N'importe quoi ! Que nenni ! Exécutez-le maintenant depuis le Workbench... Juste pour voir ! Trois possibilités :
...génère déjà un exécutable de plusieurs ko : il faut du code pour la gérer cette fenêtre ! Regardez bien la documentation de votre compilateur, elle vous indiquera comment le supprimer et diminuer ainsi la taille de votre exécutable. DICE, lui, a créé deux entrées dans le programme : le classique "main()" lorsqu'il s'exécute depuis un Shell ou un "wbmain()" lorsque c'est depuis le Workbench. Si l'utilisateur n'en fournit pas une, il utilise celle par défaut qui ne fait que terminer le programme. C'est elle qui s'exécute dans notre cas. Moralité : dans un programme devant s'exécuter depuis le Workbench, de "printf()", "puts()" et dérivés tu n'utiliseras. Notre Guru à nous Après avoir fait ce que tout le monde sait faire, innovons et créons notre propre générateur de... Guru. La fonction "DisplayAlert()" permet, en effet, de générer un écran noir, avec un cadre rouge ou jaune (à partir du Kickstart 2.0 uniquement), avec le ou les message(s) de notre choix. Voici le listing tant attendu :
Évidemment, on ne va pas programmer comme des porcs, les deux premières lignes permettent d'inclure le prototype de "DisplayAlert()" ainsi que les définitions associées. En particulier, notez bien le premier <exec/types.h>, qui définit tous les types couramment utilisés par le système. Les autres includes sont classiques. Le prototype de la fonction est le suivant :
avec...
Il se peut que cela fonctionne tel quel (!), mais vous avez plus de (mal)chance que cela se termine par le réveil du vrai Guru... En guise d'explication, une visite au sein des entrailles de l'Amiga s'impose. Comme vous le savez certainement, AmigaDOS n'est pas un bloc monolithique, genre le fameux "kernel" (noyau) cher aux Unix, mais est composé de plusieurs bibliothèques partagées dont chacune a une fonction précise. Si ça plante, il faut regarder la compilation avec GCC pour en trouver la raison. Voici le nouveau listing, qui fonctionne lui !
La seule partie logicielle fixe dans le système est l'adresse d'Exec, c'est-à-dire la bibliothèque qui s'occupe du système (allocation mémoire, chargement des bibliothèques et autres...). Eh bien oui, on a beau être relatif à fond, il faut toujours garder une référence. L'adresse où se trouve Exec est placée à l'adresse 4 de la mémoire et doit être stockée dans une variable nommée "SysBase" (logique, non ?). On peut ensuite ouvrir Intuition. Apprenez-lui le caniveau On doit rendre le système comme on l'a trouvé. Libérer la mémoire, fermer les écrans et les fenêtres... sont des choses auxquelles on doit penser. N'oubliez pas de fermer aussi les bibliothèques ouvertes ! C'est ici le rôle de la fonction "fini()" appelé par un "atexit()". On est ainsi sûr que quoi qu'il se passe, elle sera appelée. Notez que "OpenLibrary()", outre le nom, demande aussi un entier, qui est le numéro minimum de version de la bibliothèque. Si elle est antérieure, la fonction échoue en renvoyant un NULL. On verra l'utilité plus tard lorsque nous utiliserons des spécificités d'AmigaOS 2.0 ou 3.0. Ici, avec une version à 0, n'importe quelle version fonctionne et ça devrait même marcher avec un Workbench 1.0 ! On notera aussi dans ce listing le cas particulier d'Exec. Nous ne l'avons pas ouverte, mais trouvée grâce à son adresse. Ne jamais tenter de la refermer, sinon... bon vous connaissez la suite ! Inutile de préciser que ce programme ne fonctionne que depuis un Shell, vous l'aurez deviné tout seul. Non ? Bon, d'accord pour cette fois : il y a un "puts()" qui utilise le "stdout". En plus, mais vous ne pouviez pas le savoir, les arguments du Workbench ne sont pas traités de la même façon. Tout bon programmeur doit être un peu feignant C'est chiant de devoir ouvrir nous-mêmes les bibliothèques. Beaucoup de compilateurs permettent de les ouvrir et de les fermer automatiquement, sans intervention du programmeur. DICE fut le premier à le proposer et le fait tout seul. En fait, c'est même à nous de lui dire si on ne veut pas que ce soit fait, mais si vous utilisez le mécanisme ci-dessus, il sera prioritaire par rapport à l'auto-ouverture. Pour GCC, il faut lier la bibliothèque "auto" par un "-lauto". Le SAS le permet aussi mais je ne me souviens plus comment. Dans tous les cas, lisez la documentation de votre compilateur. Attention : c'est comme tout, en abuser se révèle dangereux, car à force, vous allez oublier de le faire. Et quand il s'agit d'une bibliothèque rajoutée (genre req.library), le compilateur ne saura pas comment se dépatouiller tout seul... Bon, voilà, c'est fini pour aujourd'hui. Grand merci à mes très courageux correcteurs : Alain Liverneaux et Alexandre Stotzer. Questions Voici quelques questions qui m'ont été posées par mes (très) courageux correcteurs : Pour quelqu'un qui débute vraiment en C, la ligne "*((short *)buff) = 50;" est obscure "buff" a été déclaré comme un tableau de caractères, alors qu'il doit contenir en premier un entier court (deux octets) la position en absice du premier caractère. Ici, nous souhaitons que ce soit à partir de la 50e ligne. La solution "crade" aurrait été d'initialiser les octets à la main, c'est-à-dire avec le code suivant :
Donc on met 0 dans l'octet de poids fort et 50 dans celui de poids faible, donc 0x256 + 50x1 = 50. Pour la solution la plus propre, celle employée ci-dessus, la première étape est de faire croire au compilateur, par un "cast" (short *) que "buff" est un pointeur sur un entier court. La ligne devient donc "*buff = 50;", qui se traduirait par "l'entier court pointé par "buff" prend la valeur 50". On a la même construction, mais en plus sioux, avec...
Ici, le "cast" indique qu'à l'adresse 4 se trouve le pointeur sur un pointeur (donc double indirection !) qui pointe sur une structure ExecBase... Comme résultat, on a SysBase qui contient un pointeur sur la structure en question (ouf). Comment supprimer les segments "Debug" et "Symbols" ? Sans entrer trop dans la téchnique, les fichiers exécutables sont découpés en plusieurs partie appelés segments. On y trouve, entre autres, celui du code, "Code", celui des variables initialisées, "Data", des variables non initialisées, "BBS", et d'autres qui servent au relogement en mémoire (ceux qui font que les exécutables puissent se placer n'importe où en mémoire). On trouve aussi les deux qui nous intéressent ici :
Contrairement à ce qui est dit dans l'article, il ne se passe rien lorsque je lance le HelloWorld depuis le Workbench alors qu'il est compilé avec GCC Ça dépend de la version de GCC et la manière dont il est configuré. Le mien à la version 2.7.0 et se trouve sur le CD Fred Fish 10. De toute façon, il vaut mieux éviter de lancer l'exécution de programme Shell depuis le Workbench, c'est beaucoup plus prudent !
|