Vous êtes sur la page 1sur 16

Activité Pratique n° 1 (SMP S4, 2021-2022)

Cette première activité pratique (AP1) couvre les trois premiers chapitres du cours. C'est une
activité qui n'est pas notée, et dont l'objectif est double:

Se familiariser avec les différents environnements de programmation modernes, y


compris les environnements en ligne;
Bien maîtriser les différents concepts étudiés jusqu'à présent, et qui constituent un
prérequis pour la suite du cours.

Pour cela, nous allons reprendre les exemples de programmes C++ déjà détaillés dans le cours,
ainsi que leurs équivalents en C et en Python, puis nous essayerons ensemble de:

les éditer, modifier, compiler, corriger, et exécuter en utilisant les différents outils
disponibles,
déterminer les points de ressemblance et les points de différence entre les trois langages
C, C++ et Python, notamment en ce qui concerne:

la structure générale des programmes,


les styles de programmation supportés, et
la nature des bibliothèques standards qui supportent ces styles.

Programme 1:
eq2d_v1.cpp
C'est la version 1 du premier programme C++ détaillé dans le cours, et dans le support du
cours.

Etape 1: sauvegarde du code source dans un fichier du dossier courant

1 %%writefile eq2d_V1.cpp
2 // eq2d_v1.cpp
3 // Sortie du programme si a == 0
4 #include <iostream>
5 #include <math.h>
6 using namespace std;
7 int main() {
8 float a, b, c, delta, x1, x2;
9 cout << "a = "; cin >> a;
10 if (a == 0) exit(1);
11 cout << "Entrer b et c : "; cin >> b >> c;
12 delta = b*b - 4*a*c;
13 cout << " Delta = " << delta << endl;
14 if (delta < 0) cout << " Pas de solutions réelles";
15 else if (delta == 0) cout << " x1 = x2 = " << -b/(2*a);
16 else {
17 x1 = (-b-sqrt(delta))/(2*a);
18 x2 = (-b+sqrt(delta))/(2*a);
19 cout << " x1 = " << x1 << "\n x2 = " << x2;
20 } cout << endl;
21 return 0;
22 }
23

Writing eq2d_V1.cpp

Etape 2: Vérification de l'existence du fichier sauvegardé


commande à utiliser: ls (valable en Python et Linux)
arguments de la commande utiles:

-l et -t, qui peuvent être regroupés en -lt,


eq*, pour limiter la liste à afficher.

1 ls -lt eq*

-rw-r--r-- 1 root root 588 Mar 19 07:12 eq2d_V1.cpp

Etape 3: Compilation simple de eq2_v1.cpp


Se fait à l'aide du compilateur g++ en précisant uniquement le nom du fichier source à
compiler,
Produit un fichier exécutable nommé a.out dans le répertoire courant.
Pour vérifier l'existence de l'outil g++ on peut utiliser la commande:

man g++ pour affichier son manuel (très long), s'il est installé, ou
whereis g++ pour affichier les répertoires standards qui contiennent des fichiers
nommés g++, y compris les fichiers de documentation.

1 !whereis g++

g++: /usr/bin/g++

Vérifions que le chemin qui mène à g++ fait bien partie de la variable PATH
Si c'est le cas, nous n'aurons pas à précéder g++ par son chemin d'accès (/usr/bin/g++)

1 !echo $PATH

/opt/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/us
Compilation la plus simple possible
Après compilation vérifier la création de l'exécutable a.out

1 !g++ eq2d_V1.cpp

1 ls -lt a*

-rwxr-xr-x 1 root root 13320 Mar 19 07:25 a.out*

Lancement de l'exécution de a.out


Se fait de la même façon que pour les commandes du système, c'est-à-dire à l'aide d'une
ligne de commande;
Différence avec les commandes du système: le nom de l'exécutable doit être précédé de
son chemin daccès, sauf si ce chemin fait partie de la variable d'environnement PATH;
Le répertoire courant est désigné par le nom spécial ., et le chemin qui mène à ce
répertoire par le préfixe: "./";
Le contenu de la variable PATH peut être affiché à l'aide de la commande echo $PATH.

Peut-on exécuter a.out sans préciser son chemin d'accès?


Expliquer pourquoi
Vérifier sur machine

1 # Vérification de l'exécution de a.out sans préciser son chemin d'accès


2 !a.out

/bin/bash: a.out: command not found

a.out n'est pas trouvé parce que son chemin n'existe pas dans la liste des
chemins standards qui forment PATH
A vérifier par la commande whereis

1 !whereis a.out

a:

Exécution en précisant le chemin d'accès


Faites très attention au champ de saisie des paramètres a, b et c.
Noter que b et c sont à saisir comme flot (stream) de deux nombres réels.

1 !./a.out

a = 1
Entrer b et c : 2 1
Delta = 0
x1 = x2 = -1

Remarque importante
La saisie des valeurs de a, b, et c doit se faire dans les champs de saisie rectangulaire qui
s'affichent après les deux messages "a = " et "Entrer b et c: "
Pour activer ces champs il faut cliquer sur le curseur qui s'affiche en clignottant en noir
après chaque message de saisie.
L'accès au terminal Linux de la machine virtuelle est également possible, mais c'est
payant.

1 # Autre exécution de a.out


2 !./a.out

a = 1.5
Entrer b et c : 10.2 5.1
Delta = 73.44
x1 = -6.25657
x2 = -0.543429

1 # Test du cas a == 0
2 !./a.out

a = 0

Compilation avec choix du nom de l'exécutable à produire


Se fait à l'aide de l'option -o, qui doit être suivie du nom du fichier exécutable à générer.

1 !g++ eq2d_V1.cpp -o eq2dc++1


2 !ls -lt eq*

-rwxr-xr-x 1 root root 13320 Mar 19 07:33 eq2dc++1


-rw-r--r-- 1 root root 588 Mar 19 07:12 eq2d_V1.cpp

1 # Exécution de eq2dc++1 (c++1: Version C++ de l'exemple 1)


2 !./eq2dc++1

a = 1.25
Entrer b et c : 45.6 3.8
Delta = 2060.36
x1 = -36.3965
x2 = -0.0835251

Equivalent C de eq2d_v1.cpp
Dans le cas particulier de cet exemple simple, la principale différence entre les deux langages
concerne:

La bibliothèque d'E/S (stdio.h au lieu de iostream);


L'outil d'affichage sur écran (la fonction printf au lieu de l'objet cout);
L'outil de lecture au clavier (la fonction scanf au lieu de l'objet cin).

Autre différence: la documentation des fonctions des bibliothèques standard de C est


accessible via la commande man, mais pas celle des bibliothèques C++.

Exemple: pour afficher le manuel d'utilisation de la fonction printf il suffit d'utiliser la ligne
de commande: man 3 printf;
Sans le nombre 3 (numéro de section) le manuel affiché sera celui de la commande printf
de Linux.

Sauvegarde de la version C dans un fichier nommé eq2dc_v1.c

1 %%writefile eq2d_v1.c
2 // eq2d_v1.c
3 // Equivalent C de eq2d_v1.cpp
4
5 #include <stdio.h>
6 #include <math.h>
7
8 int main() {
9 float a, b, c, delta, x1, x2;
10 printf("a = "); scanf("%f", &a);
11 if (a == 0) exit(1);
12 printf("Entrer b et c: "); scanf("%f %f", &b, &c);
13 delta = b*b - 4*a*c;
14 printf("delta = %f\n", delta);
15 if (delta < 0) printf("Pas de solutions réelles \n");
16 else if(delta == 0) printf(" x1 = x2 = %f\n",-b/(2*a));
17 else {
18 x1 = (-b-sqrt(delta))/(2*a);
19 x2 = (-b+sqrt(delta))/(2*a);
20 printf("x1 = %f\n x2 = %f\n",x1, x2);
21 } printf("\n");
22 return 0;
23 }
24

Writing eq2d_v1.c
Vérification de la création du fichier eq2d_v1.c

1 ls -lt eq*

-rw-r--r-- 1 root root 565 Mar 19 07:35 eq2d_v1.c


-rwxr-xr-x 1 root root 13320 Mar 19 07:33 eq2dc++1*
-rw-r--r-- 1 root root 588 Mar 19 07:12 eq2d_V1.cpp

Compilation simple de eq2d_v1.c


Se fait à l'aide de l'outil gcc (GNU Compiler Collection), qui fait partie intégrante de Linux.
Simple veut dire sans options de compilaltion.

1 # Recherche de gcc dans les dossiers standards


2 !whereis gcc

gcc: /usr/bin/gcc /usr/lib/gcc

1 # Lequel de ces fichiers gcc sera exécuté suite à la commande gcc


2 !which gcc

/usr/bin/gcc

1 # Commande de compilation simple


2 !gcc eq2d_v1.c

eq2d_v1.c: In function ‘main’:


eq2d_v1.c:10:15: warning: implicit declaration of function ‘exit’ [-Wimplicit-functio
if (a == 0) exit(1);
^~~~
eq2d_v1.c:10:15: warning: incompatible implicit declaration of built-in function ‘exi
eq2d_v1.c:10:15: note: include ‘<stdlib.h>’ or provide a declaration of ‘exit’
/tmp/ccarFfJT.o: In function `main':
eq2d_v1.c:(.text+0x15d): undefined reference to `sqrt'
eq2d_v1.c:(.text+0x1ab): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status

Analyse des messages d'erreur produits par gcc


Ces messages sont en fait des avertissement (warning) qui concernent les deux noms de
fonctions exit et sqrt
Pour comprendre et corriger ces erreurs il faut consulter le manuel des fonctions C exit et
sqrt.
Ces manuels appartiennent à la section 3 (bibliothèque standard de C).
Consultation du manuel de la fonction standard exit
Le manuel peut être très long,
Ne lisez pas tout, ne comprenez pas tout,
Cherchez seulement à comprendre l'origine de l'erreur.

1 !man 3 exit

EXIT(3) Linux Programmer's Manual EXIT(3)

NAME
exit - cause normal process termination

SYNOPSIS
#include <stdlib.h>

void exit(int status);

DESCRIPTION
The exit() function causes normal process termination and the value of
status & 0377 is returned to the parent (see wait(2)).

All functions registered with atexit(3) and on_exit(3) are called, in


the reverse order of their registration. (It is possible for one of
these functions to use atexit(3) or on_exit(3) to register an addi‐
tional function to be executed during exit processing; the new regis‐
tration is added to the front of the list of functions that remain to
be called.) If one of these functions does not return (e.g., it calls
_exit(2), or kills itself with a signal), then none of the remaining
functions is called, and further exit processing (in particular, flush‐
ing of stdio(3) streams) is abandoned. If a function has been regis‐
tered multiple times using atexit(3) or on_exit(3), then it is called
as many times as it was registered.

All open stdio(3) streams are flushed and closed. Files created by
tmpfile(3) are removed.

The C standard specifies two constants, EXIT_SUCCESS and EXIT_FAILURE,


that may be passed to exit() to indicate successful or unsuccessful
termination, respectively.

RETURN VALUE
The exit() function does not return.

ATTRIBUTES
For an explanation of the terms used in this section, see
attributes(7).

┌──────────┬───────────────┬─────────────────────┐
│Interface │ Attribute │ Value │
├──────────┼───────────────┼─────────────────────┤
│exit() │ Thread safety │ MT-Unsafe race:exit │
└──────────┴───────────────┴─────────────────────┘
The exit() function uses a global variable that is not protected, so it
is not thread-safe.
CONFORMING TO
POSIX.1-2001, POSIX.1-2008, C89, C99, SVr4, 4.3BSD.

NOTES
The behavior is undefined if one of the functions registered using
atexit(3) and on_exit(3) calls either exit() or longjmp(3). Note that
a call to execve(2) removes registrations created using atexit(3) and
on_exit(3).

The use of EXIT SUCCESS and EXIT FAILURE is slightly more portable (to

Remarque sur la fonction standard exit


D'après son manuel, l'utilisation normale nécessite la directive #include <stdlib.h>

Consultation du manuel de la fonction standard sqrt


Mêmes remarques que pour exit

1 !man 3 sqrt # 3 veut dire bibliothèque std C

SQRT(3) Linux Programmer's Manual SQRT(3)

NAME
sqrt, sqrtf, sqrtl - square root function

SYNOPSIS
#include <math.h>

double sqrt(double x);


float sqrtf(float x);
long double sqrtl(long double x);

Link with -lm.

Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

sqrtf(), sqrtl():
_ISOC99_SOURCE || _POSIX_C_SOURCE >= 200112L
|| /* Since glibc 2.19: */ _DEFAULT_SOURCE
|| /* Glibc versions <= 2.19: */ _BSD_SOURCE || _SVID_SOURCE

DESCRIPTION
These functions return the nonnegative square root of x.

RETURN VALUE
On success, these functions return the square root of x.

If x is a NaN, a NaN is returned.

If x is +0 (-0), +0 (-0) is returned.

If x is positive infinity, positive infinity is returned.

If x is less than -0, a domain error occurs, and a NaN is returned.


ERRORS
See math_error(7) for information on how to determine whether an error
has occurred when calling these functions.

The following errors can occur:

Domain error: x less than -0


errno is set to EDOM. An invalid floating-point exception
(FE_INVALID) is raised.

ATTRIBUTES
For an explanation of the terms used in this section, see
attributes(7).

┌─────────────────────────┬───────────────┬─────────┐
│Interface │ Attribute │ Value │
├─────────────────────────┼───────────────┼─────────┤
│sqrt(), sqrtf(), sqrtl() │ Thread safety │ MT-Safe │
└─────────────────────────┴───────────────┴─────────┘
CONFORMING TO
C99, POSIX.1-2001, POSIX.1-2008.

The variant returning double also conforms to SVr4, 4.3BSD, C89.

Remarque sur la fonction sqrt


D'après son manuel, l'utilisation normale de sqrt nécessite l'utilisation de l'option -lm dans
la commande de compilation,
Autrement, le compilateur ne comprend pas que le sqrt dont on parle est celui de la
bibliothèque standard.

Version corrigée de eq2d_v1.c


La correction consiste tout simoplement à ajouter la directive manquante #include
<stdlib.h> (ligne 6)

1 %%writefile eq2d_v1.c
2 // eq2d_v1.c
3 // Equivalent C de eq2d_v1.cpp
4
5 #include <stdio.h>
6 #include <math.h> // Compiler avec l'option -ml
7 #include <stdlib.h>
8
9 int main() {
10 float a, b, c, delta, x1, x2;
11 printf("a = "); scanf("%f", &a);
12 if (a == 0) exit(1);
13 printf("Entrer b et c: "); scanf("%f %f", &b, &c);
14 delta = b*b - 4*a*c;
15 printf("delta = %f\n", delta);
16 if (delta < 0) printf("Pas de solutions réelles \n");
17 else if(delta == 0) printf(" x1 = x2 = %f\n",-b/(2*a));
18 else {
19 x1 = (-b-sqrt(delta))/(2*a);
20 x2 = (-b+sqrt(delta))/(2*a);
21 printf("x1 = %f\n x2 = %f\n",x1, x2);
22 } printf("\n");
23 return 0;
24 }
25

Overwriting eq2d_v1.c

Correction de l'erreur concernant la fonction sqrt


Consiste tout simplement à ajouter l'option -lm à la commande de compilation

Compilation de la version corrigée avec l'option -lm de gcc


-lm veut dire faire le lien (link) avec la bibliothèque mathématique standard.

1 # Compilation avec l'option -lm (nécessaire pour les fonctions de la bibliothèque math
2 !gcc eq2d_v1.c -lm

1 ls -lt a*

-rwxr-xr-x 1 root root 8576 Mar 19 07:49 a.out*

Exécutions de a.out produit par gcc

1 !./a.out

a = 1
Entrer b et c: -2 1
delta = 0.000000
x1 = x2 = 1.000000

1 !./a.out

a = 45.123
Entrer b et c: 3.21 2.9
delta = -513.122742
Pas de solutions réelles

1 !./a.out

a = 0
Recompilation de la version C en choisissant le nom de
l'exécutable
Se fait, comme pour C++, à l'aide de l'option -o de gcc,
Sans oublier l'option -lm nécessaire pour l'utilisation de sqrt standard,
Sinon le compilateur suppose qu'on veut utiliser notre propre sqrt.

1 !gcc eq2d_v1.c -o eq2dc1 -lm


2 ! ls -lt eq*

-rwxr-xr-x 1 root root 8576 Mar 19 07:59 eq2dc1


-rw-r--r-- 1 root root 616 Mar 19 07:47 eq2d_v1.c
-rwxr-xr-x 1 root root 13320 Mar 19 07:33 eq2dc++1
-rw-r--r-- 1 root root 588 Mar 19 07:12 eq2d_V1.cpp

Equivalent Python de eq2d_v1.cpp


Python est un langage de type interprété qui s'utilise, comme tous les autres langages de ce
type, y compris le langage de commande Linux (bash), de deux façons différentes:

Mode commande ou mode interactif ou mode conversationnel (c'est ce quon fait avec le
langage bash, et on aura l'occasion de le faire aussi on Python. Si j'oublie, rappelez-moi.);
Mode programme ou scripting, come on va le tester sur cet exemple..

Un programme Python est un script dont la traduction en langage machine se fait au moment de
l'exécution par un interpréteur.

Sous Linux l'interpréteur Python est un utilitaire, nommé python3, qui s'utilise de la même façon
que g++, gcc, et n'importe quelle commande système.

1 %%writefile eq2d_v1.py
2 # eq2d_v1.py
3
4 import math # pour la fonction math.sqrt
5 import sys # pour la fonction sys.exit
6
7 a = float(input("a = "))
8
9 if (a == 0):
10 sys.exit(1)
11 b = float(input("b = "))
12 c = float(input("c = "))
13 delta = b * b - 4 * a * c
14 print("delta = ", delta)
15
16 if (delta < 0):
17 print("Pas de solutions réelles")
18 elif (delta == 0):
18 elif (delta == 0):
19 print("x1 = x2 = ", -b / (2 * a))
20 else:
21 print("x1 = ", (-b-math.sqrt(delta)) / (2*a))
22 print("x2 = ", (-b+math.sqrt(delta)) / (2*a))
23

Writing eq2d_v1.py

1 ls -lt eq*

-rw-r--r-- 1 root root 462 Mar 19 08:00 eq2d_v1.py


-rwxr-xr-x 1 root root 8576 Mar 19 07:59 eq2dc1*
-rw-r--r-- 1 root root 616 Mar 19 07:47 eq2d_v1.c
-rwxr-xr-x 1 root root 13320 Mar 19 07:33 eq2dc++1*
-rw-r--r-- 1 root root 588 Mar 19 07:12 eq2d_V1.cpp

Exécution du script eq2d_v1.py


Peut se faire au moins de deux façons différentes:

à l'aide d'une commande Linux qui fait appel à l'interpréteur python3;


à l'aide de la commande "%run"
Dans les deux cas n'oubliez pas le format de saisie des trois paramètres a, b et c.

1 !python3 eq2d_v1.py

a = 1
b = 2
c = 1
delta = 0.0
x1 = x2 = -1.0

1 # Test de eq2d_v1.py avec l'entrée a = 0


2 !python3 eq2d_v1.py

a = 0

Exécution du script eq2d_v1.py à l'aide de la commande


"%run"
Pour l'entrée a = 0, remarquer:

la communication entre programme appelant (commande %run) et le programme appelé


(le script Python),
le message indiquant que le script est arrêté par la fonction sys.exit avant sa fin normale,
la proposition, par %run, de chercher l'erreur supposée derrière cet arrêt sur le forum des
programmeurs (hackers) StackOverFlow.
1 %run eq2d_v1.py

a = 1
b = -2
c = 1
delta = 0.0
x1 = x2 = 1.0

Test du cas a == 0

1 %run eq2d_v1.py

Vérification de la communication entre %run et eq2d_v1.py en


utilisant un autre code de sortie pour la fonction sys.exit
au lieu de sys.exit(1) utiliser sys.exit(19)
vérifier que le code de retour 19 est reçu et utilisé par le programe appelant %run dans son
compte rendu.

1 %%writefile eq2d_v2.py
2 # eq2d_v2.py
3
4 import math # pour la fonction math.sqrt
5 import sys # pour la fonction sys.exit
6
7 a = int(input("a = "))
8
9 if (a == 0):
10 sys.exit(19)
11 b = int(input("b = "))
12 c = int(input("c = "))
13 delta = b * b - 4 * a * c
14 print("delta = ", delta)
15
16 if (delta < 0):
17 print("Pas de solutions réelles")
18 elif (delta == 0):
19 print("x1 = x2 = ", -b / (2 * a))
20 else:
21 print("x1 = ", (-b-math.sqrt(delta)) / (2*a))
22 print("x2 = ", (-b+math.sqrt(delta)) / (2*a))
23

Writing eq2d_v2.py

Exécution de eq2d_v2.py à l'aide de la commande %run

1 %run eq2d_v2.py

Exercices supplémentaires obligatoires (TP1)


1. En utilisant le menu Fichier/Enregistrer une copie dans drive sauvegrader une copie du
notebook sur votre drive (espace de stockage personnel),

2. Fermer le notebook actuel, en cliquant sur le croix x de son onglet dans la fenêtre de votre
navigateur,

3. Accéder à votre drive (par le menu Applications Google/Drive de l'onglet gmail) puis
chercher et ouvrir votre copie personnelle du notebook sauvegardée (en double cliquant
sur son nom),

4. En utilisant le menu Exécution/Réinitialiser l'environnement d'exécution réinitializer votre


environnement d'exécution,

5. Réexécuter le notebook en prenant soin de:

Lire très attentivement chaque cellule de texte,


Apporter des modifications aux cellules de code,
Ajouter de nouvelles cellules de texte et de code.

6. Comparer la taille des exécutables C et C++ et interpréter la différence observée.

7. Lequel des codes sources C et C++ est le plus simple? Pourquoi?

8. Lequel des exécutables C et C++ est le plus efficace? Pourquoi?

9. Comparer les codes sources C++ et Python et donner les principaux:

points communs,
points de différence.

10. Exemples de modifications conseillées dans le cas de la version C++ du programme:


Pour bien copmprendre le rôle de la directive d'inclusion #include transformez sa
ligne en un commentaire puis recompiler et essayer de bien lire et comprendre le
message d'erreur obtenu,
Faites la même chose avec les instructions using namespace std; et float a, b, c,
delta, x1, x2;

Autres exemples: en jouant sur les différentes conditions (instructions if) et leur ordre, créer de
nouvelles versions du même programme (commencre par exemple par la condition delta > 0, ou
appliquer exit quand delta==0 et non pas quand a==0, etc.)

Exercices de recherche (à préparer en petits groupes)


1. Modifier le programme de façon à permettre la répétition de son exécution plusieurs fois,
jusqu'à confirmation d'arrêt par l'utilisateur. Pour cela, on peut convenir, par exemple, de
répéter l'exécution jusqu'à la saisie d'une valeur nulle pour a.
2. Coder le calcul de delta sous la forme d'une fonction réutilisable à déclarer avant la
fonction principale main, et à définir après la définition de main.
3. Déplacer l'instruction de déclaration de la fonction delta dans un fichier à inclure nommé
smps4.hpp puis remplacer cette instruction par une directive d'inclusion.
4. Déplacer la bloc de définition de la fonction delta dans un deuxième fichier nommé
smps4.cpp.
5. Compiler la nouvelle version du programme en produisant l'exécutable sous le nom eq2d à
partir des deux fichiers sourcesqui contiennent la fonction main et la fonction delta.
6. Peut-on compiler séparément ces deux fichiers sources avnt la construction de
l'exécutable? Justifiez votre réponse et testez-la sur machine.
7. Peut-on exécuter le programme eq2d de la même façon que les commandes du système
et les outils g++, gcc et python3, c-à-d en fournissant les valeurs des paramètres a, b et c
comme arguments de la ligne de commande et non pas en les saisissant comme réponse
à des messages que le programme doit affiche à l'utilisateur? Et si l'utilisateur était un
autre programme et non pas un être humain? Justifiez votre réponse et testez-la sur
machine.
8. Quel changement peut-on alors apporter au programme pour rendre son exécution
possible à l'aide d'une ligne de commande de la forme: eq2d a b c?
9. Vérifier votre réponse sur ordinateur.

Vous aimerez peut-être aussi