From 54e9f5a936ef8e002451c1bde575f84e010f7abf Mon Sep 17 00:00:00 2001 From: Orestis <orestis.malaspinas@pm.me> Date: Wed, 1 Nov 2023 20:36:43 +0100 Subject: [PATCH] maj 2023 --- slides/compilation_make.md | 398 +++++++++++++++++++++++++++++++++++++ slides/strings.md | 72 +++++++ 2 files changed, 470 insertions(+) create mode 100644 slides/compilation_make.md create mode 100644 slides/strings.md diff --git a/slides/compilation_make.md b/slides/compilation_make.md new file mode 100644 index 0000000..92db0e0 --- /dev/null +++ b/slides/compilation_make.md @@ -0,0 +1,398 @@ +--- +title: "Compilation séparée et Makefile" +date: "2023-11-02" +--- + +# Prototypes de fonctions (1/3) + +```C +// Prototype, pas d'implémentation, juste la doc +int sum(int size, int tab[size]); +``` + +## Principes généraux de programmation + +- Beaucoup de fonctionnalités dans un code $\Rightarrow$ Modularisation. +- Modularisation du code $\Rightarrow$ écriture de fonctions. +- Beaucoup de fonctions $\Rightarrow$ regrouper les fonctions dans des fichiers séparés. + +## Mais pourquoi? + +- Lisibilité. +- Raisonnement sur le code. +- Débogage. + +## Exemple + +- Libraire `stdio.h`: `printf()`{.C}, `scanf()`{.C}, ... + +# Prototypes de fonctions (2/3) + +- Prototypes de fonctions nécessaires quand: + + 1. Utilisation de fonctions dans des fichiers séparés. + 2. Utilisation de librairies. +- Un prototype indique au compilateur la signature d'une fonction. +- On met les prototypes des fonctions **publiques** dans des fichiers *headers*, extension `.h`. +- Les *implémentations* des fonctions vont dans des fichier `.c`. + +# Prototypes de fonctions (3/3) + +## Fichier header + +- Porte l'extension `.h` +- Contient: + - définitions des types + - prototypes de fonctions + - macros + - directives préprocesseur (cf. plus loin) +- Utilisé pour décrire **l'interface** d'une librairie ou d'un module. +- Un fichier `C` (extension `.c`) utilise un header en *l'important* avec la directive `#include`{.C}: + + ```C + #include <stdio.h> // dans LD_LIBRARY_PATH + #include "chemin/du/prototypes.h" // explicite + ``` + +# Génération d'un exécutable (1/5) + +## Un seul fichier source + +{width=100%} + +# Génération d'un exécutable (2/5) + +\footnotesize + +```bash +gcc proc.c -o prog +``` + +1. **Précompilation: ** `gcc` appelle `cpp`, le préprocesseur qui effectue de la substitution de texte (`#define`, `#include`, macros, ...) et génère le code `C` à compiler, portant l'extension `.i` (`prog.i`). +2. **Compilation assembleur: ** `gcc` compile le code C en code assembleur, portant l'extension `.s` (`prog.s`). +3. **Compilation code objet: ** `gcc` appelle `as`, l'assembleur, qui compile le code assembleur en code machine (code objet) portant l'extension `.o` (`prog.o`). +4. **Édition des liens: ** `gcc` appelle `ld`, l'éditeur de liens, qui lie le code objet avec les librairies et d'autres codes objet pour produire l'exécutable final (`prog`). + +Les différents codes intermédiaires sont effacés automatiquement. + +# Génération d'un exécutable (3/5) + +## Plusieurs fichiers sources + +{width=100%} + +# Génération d'un exécutable (4/5) + +\footnotesize + +::: Main + +## `main.c` + +```C +#include <stdio.h> +#include "sum.h" +int main() { + int tab[] = {1, 2, 3, 4}; + printf("sum: %d\n", sum(tab, 4)); + return 0; +} +``` +::: + +:::::::::::::: {.columns} + +::: {.column width="45%"} + +## `sum.h` + +```C +#ifndef _SUM_H_ +#define _SUM_H_ +int sum(int tab[], int n); +#endif +``` +::: +::: {.column width="55%"} + +## `sum.c` + +```C +#include "sum.h" +int sum(int tab[], int n) { + int s = 0; + for (int i = 0; i < n; i++) { + s += tab[i]; + } + return s; +} +``` +::: + +:::::::::::::: + + +# Génération d'un exécutable (5/5) + +La compilation séparée se fait en plusieurs étapes. + +## Compilation séparée + +1. Générer séparément les fichiers `.o` avec l'option `-c`. +2. Éditer les liens avec l'option `-o` pour générer l'exécutable. + +## Exemple + +- Création des fichiers objets, `main.o` et `sum.o` + + ```bash + $ gcc -Wall -Wextra -std=c11 -c main.c + $ gcc -Wall -Wextra -std=c11 -c sum.c + ``` +- Édition des liens + + ```bash + $ gcc main.o sum.o -o prog + ``` + +# Préprocesseur (1/2) + +\footnotesize + +## Généralités + +- Première étape de la chaîne de compilation. +- Géré automatiquement par `gcc` ou `clang`. +- Lit et interprète certaines directives: + 1. Les commentaires (`//`{.C} et `/* ... */`{.C}). + 2. Les commandes commençant par `#`{.C}. +- Le préprocesseur ne compile rien, mais subtitue uniquement du texte. + +## La directive `define`{.C} + +- Permet de définir un symbole: + + ```C + #define PI 3.14159 + #define _SUM_H_ + ``` +- Permet de définir une macro. + + ```C + #define NOM_MACRO(arg1, arg2, ...) [code] + ``` + +# Préprocesseur (2/2) + +## La directive `include`{.C} + +- Permet d'inclure un fichier. +- Le contenu du fichier est ajouté à l'endroit du `#include`{.C}. +- Inclusion de fichiers "globaux" ou "locaux" + + ```C + #include <file.h> // LD_LIBRARY_PATH + #include "other_file.h" // local path + ``` +- Inclusions multiples peuvent poser problème: définitions multiples. Les headers commencent par: + + ```C + #ifndef _VAR_ + #define _VAR_ + /* commentaires */ + #endif + ``` + +# Introduction à `make` + +## A quoi ça sert? + +- Automatiser le processus de conversion d'un type de fichier à un autre, en *gérant les dépendances*. +- Effectue la conversion des fichiers qui ont changé uniquement. +- Utilisé pour la compilation: + - Création du code objet à partir des sources. + - Création de l'exécutable à partir du code objet. +- Tout "gros" projet utilise `make` (pas uniquement en `C`). + +# Utilisation de `make` + +\footnotesize + +Le programme `make` exécutera la série d'instruction se trouvant dans un `Makefile` (ou `makefile` ou `GNUmakefile`). + +## Le `Makefile` + +- Contient une liste de *règles* et *dépendances*. +- Règles et dépendances construisent des *cibles*. +- Ici utilisé pour compiler une série de fichiers sources + + ``` + $ gcc -c example.c # + plein d'options.. + $ gcc -o example exemple.o # + plein d'options + ``` + +:::::::::::::: {.columns} + +::: {.column width="55%"} + +## `Makefile` + +```bash +example: example.o + gcc -o example example.o + +exmaple.o: exmaple.c example.h + gcc -c example.c +``` +::: +::: {.column width="45%"} + +## Terminal + +```bash +$ make +gcc -c example.c +gcc -o example example.o +``` +::: +:::::::::::::: + +# Syntaxe d'un `Makefile` (1/4) + +{width=100%} + +# Syntaxe d'un `Makefile` (2/4) + +{width=100%} + +# Syntaxe d'un `Makefile` (3/4) + +{width=100%} + +# Syntaxe d'un `Makefile` (4/4) + +{width=100%} + +# Principe de fonctionnement + +1. `make` cherche le fichier `Makefile`, `makefile` ou `GNUmakefile` dans le répertoire courant. +2. Par défaut exécute la première cible, ou celle donnée en argument. +3. Décide si une cible doit être régénérée en comparant la date de modification (on recompile que ce qui a été modifié). +4. Regarde si les dépendances doivent être régénérées: + - Oui: prend la première dépendance comme cible et recommence à 3. + - Non: exécute la règle. + +`make` a un comportement **récursif**. + +# Exemple avancé + +:::::::::::::: {.columns} + +::: {.column width="55%"} + +## `Makefile` + +```bash +hello: hello.o main.o + gcc hello.o main.o -o hello + +hello.o: hello.c hello.h + gcc -Wall -Wextra -c hello.c + +main.o: main.c + gcc -Wall -Wextra -c main.c + +clean: + rm -f *.o hello + +rebuild: clean hello +``` +::: +::: {.column width="45%"} + +## Un graph complexe + +{width=100%} + +::: +:::::::::::::: + +<!-- # Factorisation + +:::::::::::::: {.columns} + +::: {.column width="55%"} +## Ancien `Makefile` + +```bash +hello: hello.o main.o + gcc hello.o main.o -o hello + +hello.o: hello.c hello.h + gcc -Wall -Wextra -c hello.c + +main.o: main.c + gcc -Wall -Wextra -c main.c + +clean: + rm -f *.o hello + +rebuild: clean hello +``` +::: +::: {.column width="45%"} + +## Nouveau `Makefile` + +```bash +CC=gcc -Wall -Wextra + +hello: hello.o main.o + $(CC) $^ -o $@ + +hello.o: hello.c hello.h + $(CC) -c $< + +main.o: main.c + $(CC) -c $< + +clean: + rm -f *.o hello + +rebuild: clean hello +``` + +::: +:::::::::::::: + +# Variables + +\footnotesize + +## Variables utilisateur + +- Déclaration + + ```bash + id = valeur + id = valeur1 valeur2 valeur3 + ``` +- Utilisation + + ```bash + $(id) + ``` +- Déclaration à la ligne de commande + + ```bash + make CFLAGS="-O3 -Wall" + ``` + +## Variables internes + +- `$@` : la cible +- `$^` : la liste des dépendances +- `$<` : la première dépendance +- `$*` : le nom de la cible sans extension + + --> diff --git a/slides/strings.md b/slides/strings.md new file mode 100644 index 0000000..912cd42 --- /dev/null +++ b/slides/strings.md @@ -0,0 +1,72 @@ +--- +title: "Chaînes de caractères" +date: "2023-11-02" +--- + +# Rappel: la chaîne de caractères + +## Existe-t-il un type `string`{.C} en `C`{.C}? + +. . . + +* Non. + +. . . + +## Qu'est-ce qu'une chaîne de caractères en C? + +. . . + +* Un tableau de `char`{.C} (entier signé 8 bits, le code ASCII de chaque caractère) + +. . . + +* qui se termine lorsqu'on rencontre le caractère `\0`{.C} (qui est le `0` du code ASCII). + +# Exemple + +```C +char *str = "HELLO !"; // statique +``` + +Est représenté par + +| `H` | `E` | `L` | `L` | `O` | | `!` | `\0`| +|------|------|------|------|------|------|------|-----| +| `72` | `69` | `76` | `76` | `79` | `32` | `33` | `0` | + +# Syntaxes alternatives + +```C +char name[10]; +name[0] = 'P'; // = 70; +name[1] = 'a'; // = 97; +name[2] = 'u'; // = 117; +name[3] = 'l'; // = 108; +name[4] = '\0'; // = 0; +char name[] = {'P', 'a', 'u', 'l', '\0'}; +``` + +# Fonctions + +\footnotesize + +- Il existe une grande quantités de fonction pour la manipulation de chaînes de caractères dans `string.h`. +- Comment les trouver? + +. . . + +```bash +$ man 3 string +``` + +- Fonctions principales: + + ```C + size_t strlen(char *str); + char *strcpy(char *dest, const char *src); + char *strncpy(char *dest, const char *src, size_t len); + int strncmp(char *str1, char *str2, size_t len); + int strcmp(char *str1, char *str2); + ``` + -- GitLab