Obligement - L'Amiga au maximum

Vendredi 23 mai 2025 - 09:37  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

Actualité (récente)
Actualité (archive)
Comparatifs
Dossiers
Entrevues
Matériel (tests)
Matériel (bidouilles)
Points de vue
En pratique
Programmation
Reportages
Quizz
Tests de jeux
Tests de logiciels
Tests de compilations
Trucs et astuces
Articles divers

Articles in English


Réseaux sociaux

Suivez-nous sur X




Liste des jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z,
ALL


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Galeries

Menu des galeries

BD d'Amiga Spécial
Caricatures Dudai
Caricatures Jet d'ail
Diagrammes de Jay Miner
Images insolites
Fin de jeux (de A à E)
Fin de Jeux (de F à O)
Fin de jeux (de P à Z)
Galerie de Mike Dafunk
Logos d'Obligement
Pubs pour matériels
Systèmes d'exploitation
Trombinoscope Alchimie 7
Vidéos


Téléchargement

Documents
Jeux
Logiciels
Magazines
Divers


Liens

Associations
Jeux
Logiciels
Matériel
Magazines et médias
Pages personnelles
Réparateurs
Revendeurs
Scène démo
Sites de téléchargement
Divers


Partenaires

Annuaire Amiga

Amedia Computer

Relec


A Propos

A propos d'Obligement

A Propos


Contact

David Brunet

Courriel

 


Programmation : C - Utiliser les printf() sous AmigaOS
(Article écrit par Stéphane Saragaglia et extrait de GuruMed.net - août 2002, mis à jour en décembre 2003)


Je vous propose un premier article qui traite de l'utilisation en langage C des entrées/sorties et du multitâche dans les applications Amiga. Cet article ne décrit pas ces aspects de manière exhaustive, mais expose des cas d'utilisation, et attire l'attention sur quelques pièges.

On ne rigole pas, c'est plus compliqué que ça en a l'air... ;). D'abord, il faut différencier "printf()" et "Printf()", et ensuite tenir compte des contextes d'appel...

Fonctions d'entrées/sorties des bibliothèques C et AmigaDOS

Les fonctions de la bibliothèque stdio du langage C (printf(), puts(), scanf(), gets()...) utilisent les variables globales d'entrées/sorties standard stdin/stdout/stderr. Par contre, les fonctions de la bibliothèque système dos.library (Write(), Printf(), PutStr(), Read()...) utilisent les champs pr_CIS/pr_COS des processus desquelles elles sont appelées.

Cela a plusieurs impacts :
  • Les fichiers d'entrées/sorties stdin/stdout et pr_CIS/pr_COS peuvent être différents.
  • Les fonctions de la dos.library ne sont utilisables que depuis des "Process" (processus), en opposition avec les "Task" (tâches).
  • Les fonctions de la bibliothèque stdio doivent être utilisées avec précautions dans les applications multi-processus.
Valeur des flux d'entrées/sorties au lancement d'un exécutable depuis le Shell ou le Workbench

Les valeurs de stdin/stdout et pr_CIS/pr_COS au démarrage d'une application dépendent du compilateur utilisé et du code de démarrage qu'il rajoute. Ci-dessous est présenté un exemple de code de démarrage qui initialise les flux (prélevé de newgccstart.lha sur Aminet). Attention, cette archive ne contient que des ébauches de prototypes d'essais, mais ça donne une idée de ce qu'on peut y trouver. ;)

newgccstart.lha

void __initstdio(void)
{
  BPTR window;
  if(_WBenchMsg!=NULL) // Executable lance depuis le WB
  {
    if((window=Open("CON:\\AUTO",MODE_NEWFILE))==NULL) // Creation d'une console
      exit(RETURN_FAIL);
    SelectInput(window);  // Redirection des entrees/sorties de la dos.library vers cette console.
    SelectOutput(window); //
  }
  stdin->file=Input();
  stdout->file=Output();
  if((stderr->file=((struct Process *)FindTask(NULL))->pr_CES)==NULL)
    stderr->file=stdout->file;
}

Ainsi, on remarque dans cet exemple que si l'exécutable est lancé depuis le Workbench, une console est créée, et les flux d'entrées/sorties de la dos.library sont redirigés vers cette console. On constate également que stdin/stdout/stderr de la bibliothèque stdio sont associés aux flux de la dos.library ; printf() et Printf() utiliseront donc la même sortie au lancement du programme.

Soit le simple programme "printf1.c" :

/* gcc -Wall -noixemul printf1.c -o printf1 -lamiga */
#include <stdlib.h>
#include <stdio.h>

#include <proto/dos.h>

int main(void)
{
 printf("printf : Salut les codeurs !\n");
 Printf("Printf : Salut les codeurs !\n");
 exit(EXIT_SUCCESS);
}

Lancement depuis le Shell : on retrouve bien les deux messages dans le Shell. Les flux d'entrées/sorties de la dos.library sont initialisés par le CLI, les flux sont dirigés vers sa console. Sauf cas particulier, le compilateur génère, comme vu ci-dessus, un exécutable qui associe aussi stdout/stdin vers les flux de la dos.library au démarrage. On a donc les deux messages.

Lancement depuis le Workbench : une fenêtre de sortie apparaît, dans laquelle s'affichent les messages. C'est le compilateur qui l'a créée !

Valeur des flux d'entrées/sorties au lancement d'un Process depuis un exécutable

Les deux chapitres ci-dessous donnent des informations sur l'initialisation des entrées/sorties de Process créés au sein d'applications.

Lancement d'un "Process-Fonction"

La fonction de lancement de Process-fonction utilisée ci-dessous est CreateNewProcTags(). Cette fonction permet de lancer un nouveau processus tout en initialisant les flux d'entrées/sorties du Process créé. Soit le simple programme suivant "printf2.c" qui crée un nouveau Process dans lequel printf() et Printf() sont appelés :

/* gcc -Wall -noixemul printf2.c -o printf2 -lamiga */
#include <stdlib.h>
#include <stdio.h>

#include <dos/dostags.h>
#include <proto/dos.h>

void MaTache(void);

int main(void)
{
 struct Process *proc = NULL;

 proc = CreateNewProcTags(NP_Entry,  MaTache,       // Point d'entrée du Process
        NP_Name,   "Mon Process", // Nom du Process
#ifdef __MORPHOS__
        NP_CodeType, MACHINE_PPC,
#endif
        TAG_DONE);

 Delay(50); // On n'a pas interet a terminer le pere avant le fils, sinon, c'est le plantage
      // (entres autres choses, les flux stdin/stdout seront fermes alors que le process fils s'en sert :( )
      // C'est un contournement, ne faites pas ca dans vos programmes ;)

 exit(EXIT_SUCCESS);
}

void MaTache(void)
{
 printf("printf : Salut les codeurs !\n");
 Printf("Printf : Salut les codeurs !\n");
}

Lancement depuis Shell et Workbech : seul le message "printf" est affiché, car pr_CIS/pr_COS du processus fils ne sont pas définis (NULL), alors que stdin/stdout reste le même pour le Process fils et le Process père...

Soit le même programme "printf3.c" avec l'initialisation de pr_CIS/pr_COS pour le Process lancé par CreateNewProcTags() :

/* gcc -Wall -noixemul printf3.c -o printf3 -lamiga */
#include <stdlib.h>
#include <stdio.h>

#include <dos/dostags.h>
#include <proto/dos.h>

void MaTache(void);

int main(void)
{
 struct Process *proc = NULL;

 proc = CreateNewProcTags(NP_Entry,  MaTache,        // Point d'entree du Process
        NP_Name,   "Mon Process",  // Nom du Process
        NP_Input,       Input(),   // Mise a jour du flux pr_CIS pour le processus fils avec celui du pere
        NP_CloseInput,  FALSE,     // Fermeture du flux a la fin du process fils : on ne ferme pas, sinon ça ferme aussi le flux du process pere
        NP_Output,       Output(), // Mise a jour du flux pr_COS pour le processus fils avec celui du pere
        NP_CloseOutput,  FALSE,    // Fermeture a la fin du process fils : on ne ferme pas, sinon ça ferme aussi le flux du process pere
#ifdef __MORPHOS__
        NP_CodeType, MACHINE_PPC,
#endif
        TAG_DONE);

 Delay(50); // On n'a pas interet a terminer le pere avant le fils, sinon, c'est le plantage
      // (entres autres choses, les flux stdin/stdout seront fermes alors que le process fils s'en sert :( )
      // C'est un contournement, ne faites pas ca dans vos programmes ;)

 exit(EXIT_SUCCESS);
}

void MaTache(void)
{
 printf("printf : Salut les codeurs !\n");
 Printf("Printf : Salut les codeurs !\n");
}

Lancement depuis le Shell et le Workbench : affichage de "printf" et "Printf". Chouette, hein ? Les fonctions InPut() et OutPut() de la dos.library retournent les champs pr_CIS/pr_COS du processus père (tels qu'initialisés). CreateNewProcTags() utilise alors ces valeurs pour initialiser les champs pr_CIS/pr_COS du processus fils.

Lancement d'un "Process-exécutable"

Ce chapitre décrit le lancement d'un Process-exécutable, et met en évidence les différences avec le lancement d'un Process-fonction.

Soit le simple programme suivant, printf6.c, qui lance printf1 :

/* gcc -Wall -noixemul printf6.c -o printf6 -lamiga */
#include <stdlib.h>
#include <stdio.h>

#include <
#include <proto/dos.h>
#include <proto/exec.h>


int main(void)
{
 BPTR seg_list = NULL;
 struct Process *proc = NULL;

 // Chargement de l'executable en memoire : printf1 qui affiche des messages avec Printf() et printf()
 // -------------------
 seg_list = LoadSeg("printf1");
 if(seg_list != 0)
 {
  // Execution de la tache printf1
  // -------------------
  proc = CreateNewProcTags(NP_Seglist,   seg_list,
         NP_Name,     "Tache printf1",
         //NP_Output,         Output(),
         //NP_CloseOutput,    FALSE,
         NP_Cli,    TRUE,
         NP_Arguments,      "",
#ifdef __MORPHOS__
         NP_CodeType, MACHINE_PPC,
#endif
         TAG_DONE);
  Delay(50);  // On n'a pas interet a terminer le pere avant le fils, sinon, c'est le plantage
     // (entres autres choses, les flux stdin/stdout seront fermes alors que le process fils s'en sert :( )
     // C'est un contournement, ne faites pas ca dans vos programmes ;)

  UnLoadSeg(seg_list);
 }

 exit(EXIT_SUCCESS);
}

Sous Shell et Workbench : il n'y a aucun affichage :(.

De la même manière que pour l'exemple printf2, il n'y pas de "Printf" car pr_CIS/pr_COS du processus fils ne sont pas initialisés. Par contre, contrairement à l'exemple printf2, stdin/stdout du processus fils ne sont pas identiques à ceux du processus père, puisqu'il s'agit du lancement d'un Process-exécutable qui initialise lui-même stdin/stdout. Comme stdin/stdout du processus fils sont initialisés à partir de pr_CIS/pr_COS du processus fils (ici NULL), il n'y a pas de message "printf". Si on décommente les lignes NP_Output et NP_CloseOutput, on obtient les affichages... :).

Modifier la valeur des flux

Ce chapitre décrit une manière de changer dans ses applications stdin/stdout et pr_CIS/pr_COS.

Soit le simple programme printf4.c :

/* gcc -Wall -noixemul printf4.c -o printf4 -lamiga */
#include <stdlib.h>
#include <stdio.h>

#include <dos/dostags.h>
#include <

void MaTache(void);

int main(void)
{
 struct Process *proc = NULL;

 proc = CreateNewProcTags(NP_Entry,  MaTache,        // Point d'entrée du Process
        NP_Name,   "Mon Process",  // Nom du Process
        NP_Input,       Input(),   // Mise a jour du flux pr_CIS pour le processus fils avec celui du pere
        NP_CloseInput,  FALSE,     // Fermeture a la fin du process fils : on ne ferme pas, sinon ça ferme aussi le flux du process pere
        NP_Output,      Output(),  // Mise a jour du flux pr_COS pour le processus fils avec celui du pere
        NP_CloseOutput, FALSE,     // Fermeture a la fin du process fils : on ne ferme pas, sinon ça ferme aussi le flux du process pere
#ifdef __MORPHOS__
        NP_CodeType, MACHINE_PPC,
#endif
        TAG_DONE);

 Delay(200);   // On n'a pas interet a terminer le pere avant le fils, sinon, c'est le plantage
     // (entres autres choses, les flux stdin/stdout seront fermes alors que le process fils s'en sert :( )
     // C'est un contournement, ne faites pas ca dans vos programmes ;)

 exit(EXIT_SUCCESS);
}

void MaTache(void)
{
 BPTR con_desc = NULL;
 BPTR old_output = NULL;

 con_desc = Open("CON:80/450/798/250/Alister Output/CLOSE/AUTO", MODE_READWRITE); // Ouverture d'une premiere console
 if(con_desc == NULL)
 {
  printf("cannot open CON:\n");
  return;
 }
 old_output = SelectOutput(con_desc); // Association du flux de sortie de la dos.library (pr_COS) avec la premiere console

 freopen("CON:80/450/798/250/Alister Output/CLOSE/AUTO", "w", stdout); // Ouverture d'une deuxieme console, et association avec stdout

 printf("printf : Salut les codeurs !\n");
 Printf("Printf : Salut les codeurs !\n");

 Delay(100);

 fclose(stdout);
 stdout = NULL;

 if(old_output != NULL) (void)SelectOutput(old_output); // Bien remettre l'ancien flux qui sera ferme par le process pere lors de sa terminaison
 if(con_desc != NULL) Close(con_desc);
}

Sous Shell et Workbench : affichage de "printf" et "Printf" dans deux consoles séparées... C'est drôle, hein ? Une variante aurait pu être d'ouvrir les nouveaux fichiers de sortie dans le processus père, et de passer en paramètre à la création du processus fils la nouvelle sortie dos.library. Cet exemple montre également qu'il peut être dangereux de jouer avec stdout/stdin dans des applications multitâches, car ces fichiers d'entrées/sorties sont utilisés au niveau "application", et pas "Process".


[Retour en haut] / [Retour aux articles]