Compare commits
No commits in common. "459cf8a8c8cec64ad0b3cb47b21fa699babf60a3" and "646e3aacc9bbfa136eda6bd3340195d0c4962675" have entirely different histories.
459cf8a8c8
...
646e3aacc9
318
chap/C.tex
318
chap/C.tex
@ -1,16 +1,10 @@
|
|||||||
\chapter{Le langage C}
|
\chapter{Langage C}
|
||||||
\label{C}\index{C}
|
\label{C}\index{C}
|
||||||
|
|
||||||
Un chapitre un peu particulier, puisque c'est le début d'une
|
Un chapitre un peu particulier, puisque c'est le début d'une
|
||||||
initiation au langage C pour les non-codeurs qui souhaitent
|
initiation au langage C pour les non-codeurs qui souhaitent
|
||||||
rentrer dans le sujet à la dure.
|
rentrer dans le sujet à la dure.
|
||||||
|
|
||||||
Certaines des explications qui vont suivre ne sont pas très
|
|
||||||
rigoureuses, mais montrent bien les principes généraux et
|
|
||||||
les erreurs classiques. La futilité des exemples est assumée.
|
|
||||||
|
|
||||||
Les détails nécessaires seront présentés dans la suite.
|
|
||||||
|
|
||||||
% ---------------------------------------------------------
|
% ---------------------------------------------------------
|
||||||
|
|
||||||
\section{Hello World}
|
\section{Hello World}
|
||||||
@ -21,14 +15,10 @@ Le tout début d'un programme en C est l'appel par
|
|||||||
le \textsl{runtime} d'une fonction
|
le \textsl{runtime} d'une fonction
|
||||||
nommée \texttt{main} qui reçoit deux paramètres
|
nommée \texttt{main} qui reçoit deux paramètres
|
||||||
dont l'utilisation est décrite un peu plus bas.
|
dont l'utilisation est décrite un peu plus bas.
|
||||||
Ces paramètres sont fournis par le système d'exploitation.
|
|
||||||
|
|
||||||
\lstinputlisting[language=c]{code/hello.c}
|
\lstinputlisting[language=c]{code/hello.c}
|
||||||
|
|
||||||
Un fois passé l'entrée, nous somme dans la partie active.
|
|
||||||
Nous appelons à ce moment la fonction \texttt{printf}
|
|
||||||
qui a pour but d'afficher sur l'écran le texte
|
|
||||||
passé en paramètre.
|
|
||||||
|
|
||||||
Voila, c'est fait. Nous savons dire bonjour au monde.
|
Voila, c'est fait. Nous savons dire bonjour au monde.
|
||||||
Point suivant~: dire boujour à quelqu'un d'autre. Et pour
|
Point suivant~: dire boujour à quelqu'un d'autre. Et pour
|
||||||
@ -40,317 +30,27 @@ de commande.
|
|||||||
\section{Arguments}
|
\section{Arguments}
|
||||||
|
|
||||||
Expliquons maintenant les deux paramètres
|
Expliquons maintenant les deux paramètres
|
||||||
\texttt{argc} et \texttt{argv} du point d'entrée du programme
|
\texttt{argc} et \texttt{argv}.
|
||||||
(la fonction main).
|
|
||||||
Le premier est le nombre de "mots" détectés par l'interpréteur
|
Le premier est le nombre de "mots" détectés par l'interpréteur
|
||||||
de commande qui va lancer votre proggy, et le second est
|
de commande qui va lancer votre proggy, et le second est
|
||||||
un tableau de chaines de caractères contenant ces différents mots.
|
un tableau contenant ces différents mots.
|
||||||
|
|
||||||
Ce petit bout de code va nous afficher tout ça~:
|
|
||||||
|
|
||||||
\lstinputlisting[language=c]{code/arguments.c}
|
\lstinputlisting[language=c]{code/arguments.c}
|
||||||
|
|
||||||
Et voici un exemple d'exécution depuis un shell~:\index{shell}
|
|
||||||
|
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
$ ./arguments un deux "trois quatre"
|
$ ./arguments un deux "trois quatre"
|
||||||
0 ./arguments
|
0 ./arguments.
|
||||||
1 un
|
1 un.
|
||||||
2 deux
|
2 deux.
|
||||||
3 trois quatre
|
3 trois quatre.
|
||||||
$
|
$
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
|
|
||||||
Nous constatons que la première valeur affichée est en fait
|
|
||||||
le nom de notre programme, ou plutôt le chemin vers le fichier
|
|
||||||
exécutable, et surtout que son indice est 0, ce qui semble
|
|
||||||
logique\footnote{Rez-de-chaussée, premier étage, toussa\dots}.
|
|
||||||
En C, les tableaux commencent toujours à l'indice 0.
|
|
||||||
|
|
||||||
Pour le traitement des options, il faut sauter à
|
|
||||||
la page \pageref{getopt}.
|
|
||||||
|
|
||||||
% ---------------------------------------------------------
|
|
||||||
\section{Les variables}
|
|
||||||
|
|
||||||
En gros, une variable du C est une zone de mémoire destinée
|
|
||||||
à contenir une valeur.
|
|
||||||
Une variable peut être caractérisée par trois choses~:
|
|
||||||
son nom, son type, et sa portée.
|
|
||||||
|
|
||||||
\textbf{Le nom} : Il doit commencer par une
|
|
||||||
lettre\footnote{To be ASCII or not to be ?} majuscule ou minuscule,
|
|
||||||
laquelle peut être suivie d'un nombre suffisant de lettres, de chiffres
|
|
||||||
et du caractère 'souligné'. La différence de casse est signifiante.
|
|
||||||
|
|
||||||
\textbf{Le type} : C'est une désignation du genre d'information
|
|
||||||
que l'on peut stocker dans une variable.
|
|
||||||
|
|
||||||
\textbf{La portée} :
|
|
||||||
|
|
||||||
% ---------------------------------------------------------
|
|
||||||
\section{Les fonctions}
|
|
||||||
|
|
||||||
Nous avons vu brièvement dans la première section de ce chapitre
|
|
||||||
la fonction \texttt{main} et ses deux paramètres.
|
|
||||||
Il est temps de préciser les détails.
|
|
||||||
|
|
||||||
% ---------------------------------------------------------
|
% ---------------------------------------------------------
|
||||||
|
|
||||||
\section{Entrées / Sorties}
|
|
||||||
\index{stdin} \index{stdout} \index{stderr}
|
|
||||||
|
|
||||||
\subsection{Les trois flux canoniques}
|
|
||||||
|
|
||||||
\texttt{stdin}, \texttt{stdout} et \texttt{stderr}\dots
|
|
||||||
|
|
||||||
Par défaut, au lancement du programme, ces trois canaux
|
|
||||||
d'entrée/sortie sont pré-connectés, et donc directement
|
|
||||||
utilisables.
|
|
||||||
Le premier (\texttt{stdin}), l'entrée standard, est connecté
|
|
||||||
au clavier du consoliste\footnote{De quel roman est tiré ce terme ?},
|
|
||||||
le second (\texttt{stdout}), la sortie standard, permet d'afficher
|
|
||||||
les résultats du programme sur l'écran,
|
|
||||||
et le troisème (), la sortie d'erreur, permet d'afficher
|
|
||||||
les éventuels messages d'erreur.
|
|
||||||
La différence entre \textsl{out} et \textsl{err} est expliquée
|
|
||||||
plus loin.
|
|
||||||
|
|
||||||
\subsection{IO de base}\index{getchar}\index{putchar}
|
|
||||||
|
|
||||||
Les fonctions \texttt{getchar} et \texttt{putchar} sont les plus
|
|
||||||
simples.
|
|
||||||
Avec elles, on peut lire un caractère depuis \texttt{stdin},
|
|
||||||
et afficher un caractère dans \texttt{stdout}. Tout cela semble
|
|
||||||
très bien, mais la fonction de lecture est piégeuse
|
|
||||||
"\textsc{It's a trap}", comme nous allons bientôt le voir.
|
|
||||||
|
|
||||||
|
|
||||||
\subsection{Écrire : \texttt{printf}}
|
|
||||||
\index{printf}
|
|
||||||
|
|
||||||
La fonction \texttt{printf} permet d'afficher le contenu d'une
|
|
||||||
(ou plusieurs)
|
|
||||||
variable sous divers formats contrôlables par un petit DSL.
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
int bar, foo = 42;
|
|
||||||
bar = printf ("foo = %d\n", foo);
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
La première ligne déclare deux variables dont une (foo) est
|
|
||||||
initialisée à une valeur connue. La seconde ligne appelle
|
|
||||||
la fonction '\texttt{printf}' avec les paramêtres appropriés et
|
|
||||||
conserve la valeur de retour de celle-ci.
|
|
||||||
|
|
||||||
Le premier de ces paramêtres, \texttt{"foo = \%d\textbackslash{}n"},
|
|
||||||
est appelé \emph{chaine de format}. C'est une chaine de caractères
|
|
||||||
que l'on peut classer en trois catégories~:
|
|
||||||
|
|
||||||
\textsl{caractères crus} : ils sont directements poussés vers la sortie.
|
|
||||||
|
|
||||||
\textsl{codes de format} : les fragments qui commencent par le
|
|
||||||
caractère '\%'.
|
|
||||||
|
|
||||||
\textsl{échappements} : les caratères précédés d'un
|
|
||||||
'\textbackslash'.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
\subsection{Lire : \texttt{scanf}}
|
|
||||||
\index{scanf}
|
|
||||||
|
|
||||||
Avez-vous bien révisé la section qui cause des pointeurs ?
|
|
||||||
|
|
||||||
% ---------------------------------------------------------
|
|
||||||
|
|
||||||
\section{Un filtre Unix}\label{filtre-unix}
|
|
||||||
|
|
||||||
Ce qu'on appelle un "filtre" est un logiciel destiné à transformer
|
|
||||||
les données qui le traversent. Pour bien comprendre, le mieux,
|
|
||||||
comme d'habitude, est un exemple. Il est un peu artificiel,
|
|
||||||
il s'agit d'éliminer les lettres \textsc{o} et \textsc{p}.
|
|
||||||
Le voici~:
|
|
||||||
|
|
||||||
\lstinputlisting[language=c]{code/no-op.c}
|
|
||||||
|
|
||||||
Démonstration~:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
$ echo apopoz | ./no-op
|
|
||||||
az
|
|
||||||
$ ./no-op < no-op.c | head -5
|
|
||||||
/*
|
|
||||||
* n-.c is an useless shell filter
|
|
||||||
*/
|
|
||||||
#include <stdi.h>
|
|
||||||
#include <ctye.h>
|
|
||||||
$
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
Pour une explication plus détaillée sur les mécanismes
|
|
||||||
utilisés et les usages possibles,
|
|
||||||
il faut voir le concept de pipeline en
|
|
||||||
page \pageref{pipeline}.
|
|
||||||
|
|
||||||
% ---------------------------------------------------------
|
|
||||||
|
|
||||||
\section{Les pointeurs}\label{pointeur}\index{pointeur}
|
|
||||||
|
|
||||||
\textbf{Ah, enfin, on a failli attendre !}
|
|
||||||
|
|
||||||
Qu'est-ce qu'un pointeur ? La réponse est multiple, et c'est
|
|
||||||
le pointeur qui fait à la fois la force et la faiblesse du C.
|
|
||||||
Pour faire simple, un pointeur est une variable qui contient
|
|
||||||
l'adresse dans la mémoire d'une autre variable.
|
|
||||||
|
|
||||||
% ---------------------------------------------------------
|
|
||||||
|
|
||||||
\section{Le préprocesseur}\index{cpp}
|
|
||||||
|
|
||||||
Nous avons déja abordé de loin la directive \texttt{\#include},
|
|
||||||
qui fait partie du préprocesseur, comme toutes les lignes
|
|
||||||
de code commençant par le caractère \textbf{\#}.
|
|
||||||
Le concept de base, qu'il faut bien capter, est que le
|
|
||||||
préprocesseur pratique des \emph{substitutions de texte}.
|
|
||||||
Pratiquement, il se passe ça~:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
#define NUMID 1664
|
|
||||||
#define FLAVOUR "tisane"
|
|
||||||
printf("La %d c'est de la %s\n", NUMID, FLAVOUR);
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
Ces trois lignes de code
|
|
||||||
(deux directives pour cpp et un appel classique de fonction)
|
|
||||||
seront converties en une seule ligne de C.
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
printf("La %d c'est de la %s\n", 1664, "tisane");
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
C'est donc cette ligne qui sera ensuite passée au vrai compilateur
|
|
||||||
pour être traduite en codes opératoires, dont l'exécution
|
|
||||||
affichera une maxime dont la véracité demande à être vérifiée
|
|
||||||
par l'expérimentation. Mais ça n'est pas fini.
|
|
||||||
|
|
||||||
Ce sympathique \textsf{préproc'} nous permet aussi de faire
|
|
||||||
de la compilation conditinnelle, et ça, c'est cool parce que
|
|
||||||
ça ouvre la porte à plein de choses.
|
|
||||||
Par exemple, l'instrumentation du code afin de faciliter
|
|
||||||
les tests et le debug.
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
...
|
|
||||||
#ifdef TRACEUR
|
|
||||||
fprintf(stderr, "pid %d was here.\n", getpid());
|
|
||||||
#endif
|
|
||||||
...
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
Et à la compilation, il vous faut passer l'option
|
|
||||||
\texttt{-DTRACEUR} à Gcc pour que ce message de trace soit
|
|
||||||
pris en compte.
|
|
||||||
|
|
||||||
% ---------------------------------------------------------
|
|
||||||
|
|
||||||
\section{Unités de compilation}
|
|
||||||
|
|
||||||
Jusque à maintenant, nous n'avons vu que des programmes dont
|
|
||||||
le code source n'était que dans un seul fichier, ce qui devient
|
|
||||||
vite ingérable pour un gros projet. C permet facilement
|
|
||||||
de faire de la compilation séparée~: chacun des fichiers source
|
|
||||||
est compilé indépendament en un fichier \textsl{objet}, lesquels
|
|
||||||
seront ensuite \textbf{liés} pour obtenir l'exécutable final.
|
|
||||||
|
|
||||||
Mais découper un gros logiciel en plusieurs fichiers source
|
|
||||||
a d'autres avantages.
|
|
||||||
|
|
||||||
% ---------------------------------------------------------
|
|
||||||
|
|
||||||
\section{Les structures}
|
|
||||||
|
|
||||||
Une structure est une sorte de boite dans laquelle on peut
|
|
||||||
ranger plusieurs variables afin de les manipuler comme
|
|
||||||
une seule entité.
|
|
||||||
|
|
||||||
% ---------------------------------------------------------
|
|
||||||
|
|
||||||
\section{Gestion de la mémoire}
|
|
||||||
\index{malloc} \index{free}
|
|
||||||
|
|
||||||
Nous avons déja entrevu la gestion « implicite » de la mémoire
|
|
||||||
avec les variables locales. Il est temps de passer à une gestion
|
|
||||||
explicite de celle-ci~:
|
|
||||||
les fonctions \texttt{malloc} et \texttt{free} sont là pour ça.
|
|
||||||
|
|
||||||
La première demande au mc/p de nous préter une certaine quantité
|
|
||||||
de mémoire, que nous pourront utiliser à notre guise.
|
|
||||||
Et la seconde restitue la zone mémoire au système sous-jacent.
|
|
||||||
|
|
||||||
Un rapide synopsis minimal d'utilisation~:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
int foo, *ptr;
|
|
||||||
if (NULL==(ptr=malloc(sizeof(int)*NBITEMS))) abort();
|
|
||||||
for (foo=0; foo<NBITEMS; foo++) ptr[foo] = rand();
|
|
||||||
do_something(ptr);
|
|
||||||
free(ptr);
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
Pour les besoins de la démo, nous avons deux variables, l'une
|
|
||||||
est entière (\texttt{foo}) et l'autre, \texttt{ptr}, est
|
|
||||||
un pointeur sur $N$ entiers.
|
|
||||||
Ce pointeur est initialisé sur la seconde ligne par un appel
|
|
||||||
à la fonction \texttt{malloc(3)} avec en paramètre le
|
|
||||||
nombre d'\textbf{octets} que nous voulons emprunter.
|
|
||||||
Ce nombre est ici calculé en multipliant le nombre de case
|
|
||||||
désiré par la taille de la case, une bonne occasion de
|
|
||||||
découvrir l'opérateur \texttt{sizeof}\dots
|
|
||||||
|
|
||||||
La boucle \texttt{for} de la ligne suivante insère des données
|
|
||||||
pertinentes dans notre tableau. Lesquelles données seront
|
|
||||||
habilement traitées sur la ligne suivante par l'appel
|
|
||||||
de cette fonction~:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
void do_something(int values[])
|
|
||||||
{
|
|
||||||
int foo;
|
|
||||||
double sum = 0.0;
|
|
||||||
for (foo=0; foo<NBITEMS; foo++) sum += (double)values[foo];
|
|
||||||
printf("sum is %g\n", sum);
|
|
||||||
}
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
Et finalement, nous avons réussi à générer un \textsl{useless number}.
|
|
||||||
Notre mission est terminée, nous rendons notre bloc de mémoire
|
|
||||||
au mc/p avec \texttt{free(ptr);}.
|
|
||||||
|
|
||||||
% ---------------------------------------------------------
|
|
||||||
|
|
||||||
\section{Gérer les options}\index{getopt}\label{getopt}
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
#include <unistd.h>
|
|
||||||
int getopt(int argc, char * const argv[], const char *optstring);
|
|
||||||
extern char *optarg;
|
|
||||||
extern int optind, opterr, optopt;
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
La page de man de getopt(3) contient des explications détaillées
|
|
||||||
et un exemple simple d'utilisation.
|
|
||||||
|
|
||||||
|
|
||||||
% =========================================================
|
|
||||||
|
|
||||||
\section{Ailleurs dans cet ouvrage}
|
|
||||||
|
|
||||||
Il y a plein d'autres exemples de code en C, sur des sujets
|
|
||||||
divers comme Open Sound Control (page \pageref{chap:OSC}) ou
|
|
||||||
libsndfile (page \pageref{chap:son}).
|
|
||||||
Et pour les gens du système~:
|
|
||||||
l'utilisation des signaux (page \pageref{get-signal}).
|
|
||||||
|
|
||||||
|
|
||||||
% ---------------------------------------------------------
|
|
||||||
|
26
chap/IPC.tex
26
chap/IPC.tex
@ -23,16 +23,15 @@ chose.
|
|||||||
\label{get-signal}
|
\label{get-signal}
|
||||||
\lstinputlisting[language=c]{code/get-signal.c}
|
\lstinputlisting[language=c]{code/get-signal.c}
|
||||||
|
|
||||||
Quand ce processus recevra le signal, la fonction \texttt{attraper}
|
|
||||||
sera appelée de façon \textsl{asynchrone} et positionnera le drapeau.
|
|
||||||
C'est dans le terme \textsl{asynchrone} que le diable a caché
|
|
||||||
les détails.
|
|
||||||
|
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
|
fubar $ make get-signal
|
||||||
|
gcc -Wall get-signal.c -o get-signal
|
||||||
fubar $ ./get-signal &
|
fubar $ ./get-signal &
|
||||||
[1] 14001
|
[1] 14001
|
||||||
fubar $ kill me, my pid is 14001
|
fubar $ kill me, my pid is 14001
|
||||||
kill -USR1 14001
|
kill -USR1 14001
|
||||||
|
fubar $ count is 15
|
||||||
|
kill -USR1 14001
|
||||||
fubar $ count is 22
|
fubar $ count is 22
|
||||||
kill %1
|
kill %1
|
||||||
fubar $
|
fubar $
|
||||||
@ -40,23 +39,6 @@ fubar $
|
|||||||
fubar $
|
fubar $
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
|
|
||||||
Comme on peut le constater, le principe est simple. Un signal est
|
|
||||||
une interruption d'un processus qui, en dehors de sa présence, ne
|
|
||||||
transfère que peu d'information. Le principe est simple, d'accord,
|
|
||||||
mais la mise en œuvre l'est moins.
|
|
||||||
Cet exemple peut être considéré comme obsolète, et la
|
|
||||||
\textsl{manpage}\footnote{Mais qui lit le man, de nos jours ?}
|
|
||||||
confime bien.
|
|
||||||
|
|
||||||
\begin{quote}
|
|
||||||
The only portable use of signal() is to set a signal's disposition to
|
|
||||||
SIG\_DFL or SIG\_IGN. The semantics when using signal() to establish a
|
|
||||||
signal handler vary across systems (and POSIX.1 explicitly permits this
|
|
||||||
variation); \textbf{do not use it for this purpose}.
|
|
||||||
\end{quote}
|
|
||||||
|
|
||||||
Vous voilà prévenus, la suite bientôt\dots
|
|
||||||
|
|
||||||
% ================================================================
|
% ================================================================
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,34 +1,16 @@
|
|||||||
% ----------------------------------------------------------
|
% ----------------------------------------------------------
|
||||||
\chapter{Dosbox}
|
\chapter{Dosbox}
|
||||||
\index{dosbox}\label{chap:dosbox}
|
\index{dosbox}
|
||||||
|
|
||||||
Dosbox est un émulateur de machine MS-DOS avec le son et
|
Dosbox est un émulateur de machine MS-DOS avec le son et
|
||||||
le graphique. Il ne nécessite pas de système d'exploitation.
|
le graphique. Il ne nécessite pas de système d'exploitation.
|
||||||
|
|
||||||
% ----------------------------------------------------------
|
|
||||||
\section{Configuration}
|
|
||||||
|
|
||||||
La configuration de Dosbox est par défaut dans le fichier
|
|
||||||
\texttt{~/.dosbox/dosbox-0.74-2.conf}. Vous remarquerez
|
|
||||||
que le numéro de version est \textbf{dans} le nom de
|
|
||||||
ce fichier.
|
|
||||||
|
|
||||||
C'est à la fin de celui-ci, dans la section
|
|
||||||
\texttt{autoexec} que vous pouvez rajouter ce genre de lignes~:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
mount C: /home/tth/Essais/DosBox/C
|
|
||||||
mount D: /home/tth/Essais/DosBox/D
|
|
||||||
keyb fr
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
% ----------------------------------------------------------
|
% ----------------------------------------------------------
|
||||||
\section{Popcorn}
|
\section{Popcorn}
|
||||||
\index{Popcorn}
|
\index{Popcorn}
|
||||||
|
|
||||||
\textbf{Popcorn} est un jeu de cassebrique écrit dans les années
|
\textbf{Popcorn} est un jeu de cassebrique écrit dans les années
|
||||||
80 pour tirer la quintessence des cartes graphiques CGA\index{CGA}.
|
80 pour tirer la quintessence des cartes graphiques CGA\index{CGA}.
|
||||||
Écrit, sans le moindre doute, au « ras du métal ».
|
|
||||||
|
|
||||||
% ----------------------------------------------------------
|
% ----------------------------------------------------------
|
||||||
% ----------------------------------------------------------
|
% ----------------------------------------------------------
|
||||||
|
Loading…
Reference in New Issue
Block a user