Skip to content

Programmation en C sous UN*X – TP N°1

25 février 2013

1. Un petit rien

Pour commencer, nous allons écrire, compiler et exécuter le plus petit programme en C possible.
Ouvrez le terminal.
Tapez la commande suivante, tout en minuscules (le C comme Unix sont sensibles à la casse) :

echo "main(){}">rikiki.c

Ça y est, félicitations : vous avez écrit un programme en C ! Et vous l’avez enregistré dans le fichier « rikiki.c » !
Si si ! Vérifiez : affichez le contenu du répertoire courant avec la commande :

ls

Vous voyez le fichier rikiki.c ? C’est votre programme source.

echo est une commande du shell Unix qui, comme son nom l’indique, renvoie en écho le texte que vous lui avez crié donné en paramètre. Renvoie vers où ? vers la sortie standard, c’est-à-dire normalement vers l’écran, mais ici la sortie standard a été redirigée (détournée) vers le fichier rikiki.c avec l’opérateur de redirection >.

Si vous n’êtes toujours pas convaincu, affichez le contenu du fichier avec la commande :

cat rikiki.c

vous devriez retrouver votre programme :

main(){}

Ce programme est en langage C. Pour que la machine le comprenne et l’exécute, il faut le traduire en langage machine. Pour cela, compilez-le avec la commande :

gcc rikiki.c

GCC (GNU Compiler Collection) est un compilateur qui comprend plusieurs langages. Comme le nom du fichier donné en paramètre se termine par .c (attention ! il faut qu’il se termine par .c en minuscule), il va considérer que le programme est en C et va le compiler (le traduire) en langage machine dans un fichier exécutable binaire.

Par défaut, le nom du fichier exécutable obtenu est a.out (assembler output).

GCC ne renvoie aucun message si tout se passe bien, sinon il peut afficher des erreurs ou des avertissements.
Vérifiez avec la commande ls que a.out a bien été créé par GCC.

Pour savoir ce que fait le programme, il faut demander au système de l’exécuter. Pour cela, il suffit de taper le nom du fichier exécutable précédé du chemin où il se trouve. Comme il est dans le répertoire courant (symbolisé par un point . sous Unix) il suffit de taper la commande :

./a.out

Le résultat de l’exécution doit donner… rien du tout !

En effet, ce premier programme n’effectue aucun affichage (et rien d’autre non plus d’ailleurs). Mais il nous a permis de voir les étapes de la compilation et de l’exécution.

Examinons-le :

main(){}

Il ne comporte qu’une ligne, qui est en fait une définition de fonction.
Le nom de la fonction est main.
Le corps de la fonction est vide : il n’y a rien dans le bloc d’instructions délimité par les accolades { (début de bloc) et } (fin de bloc).

La définition de la fonction main() est obligatoire dans tout programme en C. C’est la fonction principale, qui est le point de départ du programme et dont les instructions sont exécutées en premier.

Si nous voulons que notre programme fasse quelque chose, il faut donc mettre au moins une instruction dans le bloc du corps de main() entre les accolades.

2. Hello, world!

Nous allons créer le fichier texte hello.c qui contiendra le programme source de notre deuxième exemple. Dans le terminal, tapez la commande :

kwrite hello.c &

L’éditeur Kwrite s’ouvre dans une fenêtre.
Si cela ne fonctionne pas, c’est que Kwrite n’est pas installé, essayez alors avec Gedit, en remplaçant la commande kwrite ci-dessus par gedit

(Remarque : le & à la fin de la commande est une astuce pour pouvoir entrer d’autres commandes dans le terminal après sans avoir à fermer la fenêtre de l’éditeur)

Tapez dans la fenêtre de l’éditeur de texte le programme suivant (sans les numéros des lignes bien sûr) :

main()
{
    puts("Hello, world!");
}

Enregistrez votre programme (Ctrl+S ou bouton Enregistrer) puis revenez au terminal et compilez le programme avec :

gcc hello.c

Exécutez le programme avec :

./a.out

… et admirez le résultat ! Si tout s’est bien passé, votre programme a affiché :

Hello, world!

Il a ensuite terminé son exécution et a rendu la main à l’interpréteur de commandes du terminal.

Observons encore une fois notre programme ci-dessus.
Remarquez que nous avons mis les accolades chacune seule sur une ligne. Le choix de ce style permet de veiller à ce que chaque accolade ouvrante ait une accolade fermante correspondante qui soit alignée avec elle. Quand on a beaucoup de blocs imbriqués, c’est très utile.
Le C n’impose pas de style particulier pour la présentation, mais il est conseillé de ne pas abuser de cette liberté pour écrire du code incompréhensible. Le programme doit rester bien lisible pour être maintenable.

La seule différence entre le premier programme et le deuxième est donc l’instruction de la ligne 3. Cette instruction est construite grâce à une expression et un point-virgule. La plupart des instructions en C se terminent par un point-virgule. Ce n’est pas un séparateur d’instructions (comme en Pascal) mais il fait partie de l’instruction. La plus petite instruction en C, l’instruction vide, est constituée d’un simple point-virgule (nous aurons l’occasion de l’utiliser dans les boucles notamment).

L’expression qui constitue (avec le point-virgule) l’instruction de la ligne 3 est un appel à une fonction. On appelle une fonction en écrivant son nom suivi de parenthèses. Si la fonction nécessite des paramètres, on les met entre les parenthèses en les séparant par des virgules.

La fonction appelée ici est puts(), qui est une fonction de la bibliothèque standard stdio (standard input/output) qui permet d’afficher sur la sortie standard (ici c’est l’écran) le contenu de la chaîne de caractères qui lui est donnée en argument.

Remarquons qu’une chaîne de caractères s’écrit en C avec des guillemets " autour.

Il existe une autre fonction de la bibliothèque stdio qui permet d’afficher à l’écran : printf()
Modifiez votre programme de cette façon :

main()
{
    puts("Hello, world!");
    printf("Salam alikoum !");
}

Compilez-le. Cette fois-ci, le compilateur vous donne un message.

hello.c: In function ‘main’:
hello.c:4:5: attention : incompatible implicit declaration of built-in function ‘printf’ [enabled by default]

C’est un avertissement (warning). Les avertissements ressemblent à des erreurs mais ne sont pas fatals : ils n’empêchent pas la compilation de se terminer. Essayez d’exécuter votre programme, vous verrez qu’il fonctionne bien.

Attention, ne négligez pas les avertissements : très souvent, ils montrent un défaut dans votre programme qui peut vous causer de gros ennuis par la suite.

Mais avant de nous en occuper, nous allons d’abord régler un petit problème : les programmes que nous compilons s’appellent tous a.out, et vous avez dû remarquer que le dernier écrase toujours le précédent. En fait, la syntaxe de la commande gcc donnée précédemment est incomplète. On ne l’utilise jamais comme cela (sauf si on est vraiment pressé).

Voici la syntaxe qu’il est conseillé plutôt d’utiliser. Essayez-la :

gcc hello.c -o hello -Wall -g -std=c99

– l’option -o permet de préciser le nom du fichier exécutable à obtenir : il vaut mieux avoir un exécutable qui s’appelle hello que a.out
– l’option -Wall (attention, W majuscule) permet d’activer tous les avertissements : ils sont vraiment très utiles.
– l’option -g permet d’ajouter des informations pour la détection des erreurs (exemple : si vous écrivez printF au lieu de printf, elle permet de préciser le numéro de la ligne où se trouve l’erreur).
– l’option -std=c99 permet d’utiliser la norme de 1999 plutôt que celle de 1990.

Les messages du compilateur sont plus nombreux. L’option -Wall a activé l’affichage de plusieurs avertissements :

hello.c:1:1: attention : return type defaults to ‘int’ [-Wreturn-type]
hello.c: In function ‘main’:
hello.c:3:5: attention : implicit declaration of function ‘puts’ [-Wimplicit-function-declaration]
hello.c:4:5: attention : implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
hello.c:4:5: attention : incompatible implicit declaration of built-in function ‘printf’ [enabled by default]

Il ne faut pas oublier que même si le programme est compilé et fonctionne, ces avertissements dénotent des erreurs de programmation.

Trois des avertissements concernent les fonctions puts et printf. Le compilateur se plaint car il n’a pas trouvé la déclaration de ces fonctions et les a donc déclarées de façon implicite (par défaut). Le compilateur a corrigé l’erreur mais nous avons eu de la chance que ces fonctions soient si simples, cela aurait pu être plus grave avec d’autres fonctions. La solution est d’inclure dans notre programme les déclarations que l’on trouve dans un fichier fait pour cela. En effet, toutes les fonctions de la bibliothèque stdio se trouvent prêtes dans le fichier d’en-tête stdio.h, qu’il suffit d’inclure en ajoutant au début de notre programme :

#include <stdio.h>

Cette ligne est une directive du préprocesseur. Avant de compiler un programme, le compilateur appelle toujours le préprocesseur qui va remplacer cette ligne par le contenu du fichier d’en-tête stdio.h. Ainsi, les déclarations de printf() et puts() seront incluses dans notre programme.
Essayons donc de compiler notre nouveau programme :

#include <stdio.h>
main()
{
    puts("Hello, world!");
    printf("Salam alikoum !");
}

Le premier avertissement de tout à l’heure est toujours là. Il concerne notre fonction main() elle-même. Il indique que la fonction main() retourne par défaut un entier (int). En effet, nous n’avons pas indiqué quel était le type de retour de main() et dans la norme du C, c’est une faute, même si elle est corrigée par défaut par le compilateur. Dans la norme, il y a seulement deux façons de définir main(), la première est comme suit (nous parlerons plus tard de la deuxième) :

int main(void)

(suivie bien sûr du corps de la fonction entre accolades)
int est le type de retour (entier) et void indique qu’il n’y a pas de paramètres.

Quel est cet entier retourné par main() ? C’est le code de sortie du programme : un nombre qui est renvoyé au système d’exploitation pour qu’il sache si le programme s’est terminé sans erreur. Sous Unix et la plupart des systèmes, le code doit être zéro quand le programme se termine correctement et un entier non nul sinon. Mais ce n’est pas le cas pour tous les systèmes. Il existe des constantes pour le code de sortie dans le fichier d’en-tête stdlib.h : ce sont EXIT_SUCCESS et EXIT_FAILURE.

Voici donc notre programme, corrigé selon la norme, pour qu’il se compile sans avertissements :

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    puts("Hello, world!");
    printf("Salam alikoum !\n");
    return EXIT_SUCCESS;
}

Remarquez que l’on y a ajouté aussi le code de caractère \n à la fin de la deuxième chaîne : cela permet de retourner à la ligne, car puts() le fait automatiquement mais pas printf(). puts() est plus approprié que printf pour afficher une chaîne de caractères mais printf() permet de combiner plusieurs types à l’affichage.

3. Calcul

/*
 *  Licence informatique 2e année - 2012-2013
 *  TP - Calcul
 *  Fichier source : calcul.c
 *  Compiler avec :
 *  gcc -Wall -o calcul calcul.c -g -std=c99
 *  Auteur : Amine "nh2" Brikci-Nigassa
 */
 
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    puts("--- Calcul ---");
    printf("1er nombre : ");
    int a;           // déclaration de l'entier a
    scanf("%d",&a);  // lecture de a
    printf("2e nombre (non nul) : ");
    int b;
    scanf("%d",&b);
    if (b == 0) {    // test d'égalité : double égal
        puts("Erreur !! 2e nombre nul !");
        return EXIT_FAILURE;  // sortie du programme
    } else {
        int somme = a + b;    // déclaration + affectation (égal)
        printf("%d + %d = %d\n", a, b, somme);
        int produit = a * b;
        printf("%d x %d = %d\n", a, b, produit);
        int quotient = a / b;
        printf("%d : %d = %d\n", a, b, quotient);
        int reste = a % b;
        printf("%d = %d x %d + %d\n", a, b, quotient, reste);        
        return EXIT_SUCCESS;
    }
}

Essayez ce programme.

Les commentaires sont délimités soit par /* et */ soit par // et la fin de la ligne.

Remarquez la syntaxe utilisée pour la déclaration des variables (type nom;). Contrairement au Pascal, les déclarations peuvent être mélangées aux instructions (depuis la norme de 1999). Souvent, on préfère déclarer une variable au dernier moment, juste avant de l’utiliser.

La fonction scanf() permet de lire l’entrée standard (ici le clavier). On utilise le code format %d pour des entiers en base 10. La variable à lire est précédée du symbole & qui signifie « adresse mémoire de » (scanf() ne reçoit pas la variable mais son adresse en mémoire, pour pouvoir en modifier le contenu).

La syntaxe de if est la suivante :

if (condition)
    instruction_si_vrai;
else
    instruction_si_faux;

La condition doit obligatoirement être entourée de parenthèses.
N’oubliez pas les points-virgules, ils font partie des instructions.

Exercice

Écrivez un programme en C permettant de calculer les racines réelles et complexes d’une équation du second degré à une inconnue.
Indications :
– Le type à utiliser pour déclarer des réels est float ou double. On préfère généralement le type double.
– Le code format pour la lecture d’un réel avec scanf() est %f pour un float et %lf pour un double.
– Le code format pour l’écriture d’un réel avec printf() est %f ou %g pour les deux types. On préférera %g dans cet exercice, mais essayez d’abord avec %f.
– La fonction racine carrée est sqrt() et elle est déclarée dans le fichier d’en-tête math.h. Attention : pour que la bibliothèque math soit utilisée à la compilation (à l’édition de liens), il faut ajouter l’option -lm à la commande gcc.
– L’opérateur logique ET s’écrit && en C
– L’opérateur logique OU s’écrit || en C
– L’opérateur logique NON s’écrit ! en C
– Les opérateurs de comparaison inférieur, supérieur, inf. ou égal, sup. ou égal, égal et différent s’écrivent respectivement < > <= >= == !=

Publicités
Laisser un commentaire

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment cette page :