edix_shell_et_c(7f) edix_shell_et_c(7f)

edix_shell_et_c - Utiliser le C pour créer des commandes de type shell

Lorsqu'on souhaite créer de nouvelles commandes, à utiliser dans un terminal comme les commandes officielles du shell posix (voir edix_shell(7f) et edix_shell_posix(7f)), la démarche la plus simple consiste à créer des scripts shell : programmer chaque nouvelle commande en combinant des commandes shell existantes (programmer en langage shell) et en les regroupant dans un fichier exécutable (voir edix_shell_script(7f)). Mais dans certains cas, il est plus simple de programmer les nouvelles commandes en utilisant le langage C (voir edix_c(7f)).

Nous donnons ici quelques conseils pratiques pour ce type de programmation C dans le contexte des travaux pratiques sous edix.

Nous prendrons l'exemple suivant : nous souhaitons créer

  • une commande nommée sin_sur_sin.exe qui prend en entrée deux réels a et b et qui renvoit en sortie le résultat du calcul sin(a)/sin(b) ;
  • une commande nommée cos_sur_cos.exe qui prend en entrée deux réels a et b et qui renvoit en sortie le résultat du calcul cos(a)/cos(b).
On donne un nom au projet : trigo_sur_trigo.

A écrire : entrée standard, sortie standard, sortie d'erreur, etc.

On programme les commandes comme si on souhaitait les appeler comme des fonctions à l'intérieur d'un programme C (on les appelera effectivement depuis des programmes main, voir ci-dessous).

Rien n'est obligatoire, mais dans ce qui suit nous faisons attention à utiser un même prefix pour tous les objets C que nous définissions dans notre projet de développement. On anticipe ainsi l'idée du développement d'une bibliothèque. Le prefix sera trigo_sur_trigo.

Nous créons deux premiers fichiers :

  • trigo_sur_trigo.h qui est un fichier d'entêtes ;
  • trigo_sur_trigo.c qui est un fichier source où nous programmons les fonctions elles-mêmes.

Les deux fonctions C sont nommées trigo_sur_trigo_sin_sur_sin et trigo_sur_trigo_cos_sur_cos.

Le contenu du fichier d'entêtes trigo_sur_trigo.h est le suivant. Il définit les entrées et sorties deux deux fonctions :

#ifndef TRIGO_SUR_TRIGO_H
#define TRIGO_SUR_TRIGO_H
extern int
trigo_sur_trigo_sin_sur_sin

(double* sin_sur_sin,
double a,
double b); extern int trigo_sur_trigo_cos_sur_cos
(double* sin_sur_sin,
double a,
double b); #endif

Le contenu du fichier source trigo_sur_trigo.c est le suivant. Il définit les deux fonctions elles-même, c'est à dire le calcul de sin(a)/sin(b) ou de cos(a)/cos(b), ainsi que la gestion des exceptions (la gestion des erreurs) :

#include "trigo_sur_trigo.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
int
trigo_sur_trigo_sin_sur_sin

(double* sin_sur_sin,
double a,
double b) {
int err = 0;
*sin_sur_sin = sin(a)/sin(b);
if (!isfinite(*sin_sur_sin)) {
goto error;
} exit:
return err; error:
err = 1;
goto exit; } int trigo_sur_trigo_cos_sur_cos
(double* cos_sur_cos,
double a,
double b) {
int err = 0;
*cos_sur_cos = cos(a)/cos(b);
if (!isfinite(*cos_sur_cos)) {
goto error;
} exit:
return err; error:
err = 1;
goto exit; }

On crée deux fichiers trigo_sur_trigo_sin_sur_sin_main.c et trigo_sur_trigo_cos_sur_cos_main.c qui sont des fonctions main. C'est en les compilant que l'on produira les deux commandes sin_sur_sin.exe et cos_sur_cos.exe.

La fonction trigo_sur_trigo_sin_sur_sin_main.c reçoit les deux valeurs de a et b sur l'entrée standard et produit

  • la valeur de sin(a)/sin(b) sur la sortie standard ;
  • un éventuel message d'erreur sur la sortie d'erreur standard ;
  • un code de sortie (0 pour un succès ou 1 pour un échec).
Le contenu de la fonction est le suivant :

#include "trigo_sur_trigo.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char* argv[])
{

double a = -1.;
double b = -1.;
double sin_sur_sin = -1.;
int err = 0;
if (argc!=3) {
fprintf(stderr, "Arguments: %s a bn", argv[0]);
goto error;
}
a=atof(argv[1]);
b=atof(argv[2]);
err = trigo_sur_trigo_sin_sur_sin(&sin_sur_sin,a,b);
if (err!=0) {
fprintf(stderr, "Erreur dans la fonction trigo_sur_trigo_sin_sur_sinn");
goto error;
}
printf("%.17gn", sin_sur_sin); exit:
return err; error:
err = 1;
goto exit; }

De même, le contenu de la fonction trigo_sur_trigo_cos_sur_cos_main.c est le suivant :

#include "trigo_sur_trigo.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char* argv[])
{

double a = -1.;
double b = -1.;
double cos_sur_cos = -1.;
int err = 0;
if (argc!=3) {
fprintf(stderr, "Arguments: %s a bn", argv[0]);
goto error;
}
a=atof(argv[1]);
b=atof(argv[2]);
err = trigo_sur_trigo_cos_sur_cos(&cos_sur_cos,a,b);
if (err!=0) {
fprintf(stderr, "Erreur dans la fonction trigo_sur_trigo_cos_sur_cosn");
goto error;
}
printf("%.17gn", cos_sur_cos); exit:
return err; error:
err = 1;
goto exit; }

On utilise le fichier Makefile suivant :

.POSIX:
CC = gcc
CFLAGS = -I.
LDLIBS = -lm
DEPS = trigo_sur_trigo.h
OBJ_PROG1 = trigo_sur_trigo_sin_sur_sin_main.o trigo_sur_trigo.o
OBJ_PROG2 = trigo_sur_trigo_cos_sur_cos_main.o trigo_sur_trigo.o
EXE = 

sin_sur_sin
cos_sur_cos all: $(EXE) clean: rm -f *.o *.exe sin_sur_sin: $(OBJ_PROG1) $(CC) $(CFLAGS) -o $@.exe $(OBJ_PROG1) $(LDLIBS) cos_sur_cos: $(OBJ_PROG2) $(CC) $(CFLAGS) -o $@.exe $(OBJ_PROG2) $(LDLIBS) .c.o: $(CC) $(CFLAGS) -c $< -o $@

On compile avec

etudiant:~ $ make clean ; make

et on exécute les deux commandes (pour a=0.4 et b=0.8) avec

etudiant:~ $ sin_sur_sin.exe 0.4 0.8
etudiant:~ $ cos_sur_cos.exe 0.4 0.8

Vous devriez obtenir 0.54285221419161933 et 1.3220211340665089.

edix_c(7f), edix_shell(7f), edix_shell_posix(7f), edix_shell_script(7f)

2026-05-17 UNIX