Algorithmes et C appliqués aux Systèmes Numériques
Les appels systèmes, les erreurs et la chaine de compilation

John Samuel
CPE Lyon

Année: 2022-2023
Courriel: john(dot)samuel(at)cpe(dot)fr

Creative Commons License

3.1. Algorithmes et C: Objectifs

Objectifs

3.2. Les variables constantes

Une variable constante

/* Une variable constante
*/

#include <stdio.h>


int main() {
  const int year = 2017; // une variable constante
 year = 2019; // tentative de modification d'une variable constante
 printf("C'est l'annee %d", year);
  return 0;
}

3.2. Les variables constantes

Erreur pendant la compilation

$ gcc bonjour.c
const.c: In function ‘main’:
const.c:5:8: error: assignment of read-only variable ‘year’
year = 2019;

3.3. La portée des variables

Une variable globale

/* affiche un message à l'écran en utilisant une variable globale
*/

#include <stdio.h>
int year = 2017 // une variable globale;

int main() {
  printf("C'est l'annee %d", year); //affiche 2017
  return 0;
}

3.3. La portée des variables

Une variable globale

/* affiche un message à l'écran en utilisant une variable globale
*/

#include <stdio.h>


int main() {
  printf("C'est l'annee %d", year);
  return 0;
}
int year = 2017 // une variable globale;

3.3. La portée des variables

Erreur pendant la compilation

$ gcc bonjour.c
bonjour.c: In function ‘main’:
bonjour.c:5:30: error: ‘year’ undeclared (first use in this function)
5 | printf("C'est l'annee %d", year);
| ^~~~
bonjour.c:5:30: note: each undeclared identifier is reported only once for each function it appears in

3.3. La portée des variables

Une variable locale

/* affiche un message à l'écran en utilisant une variable locale
*/

#include <stdio.h>
int year = 2017 // une variable globale;

int main() {
  int year = 2018 // une variable locale;
  printf("C'est l'annee %d", year); //affiche 2018
  return 0;
}

3.3. La portée des variables

Une variable locale

/* affiche un message à l'écran en utilisant une variable locale
*/

#include <stdio.h>
int year = 2017 // une variable globale;

int main() {
  int year = 2018 // une variable locale;
  {
   int year = 2019 // une variable locale;
   printf("C'est l'annee %d", year); //affiche 2019
  }
  printf("C'est l'annee %d", year); //affiche 2018
  return 0;
}

3.4. Le passage de paramètres

1. Passage par valeur

void echange( int a, int b ) {
  int temp = a;
  a = b;
  b = temp;
}

int main() {
  int a = 10;
  int b = 20;
  echange(a, b);
  printf("a: %d, b: %d", a, b); //affiche 10, 20
  return 0;
}

3.4. Le passage de paramètres

2.1 Passage par référence: une variable

void echange( int *a, int *b ) {
  int temp = *a;
  *a = *b;
  *b = temp;
}

int main() {
  int a = 10;
  int b = 20;
  echange(&a, &b);
  printf("a: %d, b: %d", a, b); //affiche 20, 10
  return 0;
}

3.4. Le passage de paramètres

2.2. Passage par référence: un tableau

void affichage( char message[10] ) {
  printf("%s\n", message);
}

int main() {
  char message[10] = "Bonjour";
  affichage(message);
  return 0;
}

3.4. Le passage de paramètres

2.2. Passage par référence: un tableau

void affichage( char message[] ) {
  printf("%s\n", message);
}

int main() {
  char message[10] = "Bonjour";
  affichage(message);
  return 0;
}

3.4. Le passage de paramètres

2.2. Passage par référence: un tableau

void affichage( char *message ) {
  printf("%s\n", message);
}

int main() {
  char message[10] = "Bonjour";
  affichage(message);
  return 0;
}

3.4. Le passage de paramètres

2.2. Passage par référence: un tableau

void affichage( int tableau[2][2] ) {
  for ( int i = 0; i < 2; i++) {
    for ( int j = 0; j < 2; j++) {
     printf("%d\n",  tableau[i][j]);
    }
  }
}

int main() {
  int prix[2][2] = {
      {11, 12},
      {13, 14}};
  affichage(prix);
  return 0;
}

3.4. Le passage de paramètres

2.2. Passage par référence: un tableau

void affichage( int tableau[][] ) {
  for ( int i = 0; i < 2; i++) {
    for ( int j = 0; j < 2; j++) {
     printf("%d\n",  tableau[i][j]);
    }
  }
}

int main() {
  int prix[2][2] = {
      {11, 12},
      {13, 14}};
  affichage(prix);
  return 0;
}

3.4. Le passage de paramètres

2.2. Passage par référence: un tableau

Erreur pendant la compilation

$ gcc tableau.c
tableau.c:3:21: error: array type has incomplete element type ‘int[]’
3 | void affichage( int tableau[][] ) {
| ^~~~~~~
tableau.c:3:21: note: declaration of ‘tableau’ as multidimensional array must have bounds for all dimensions except the first
tableau.c: In function ‘main’:
tableau.c:15:13: error: type of formal parameter 1 is incomplete
15 | affichage(prix);

3.4. Le passage de paramètres

2.2. Passage par référence: un tableau

void affichage( int tableau[][2] ) {
  for ( int i = 0; i < 2; i++) {
    for ( int j = 0; j < 2; j++) {
     printf("%d\n",  tableau[i][j]);
    }
  }
}

int main() {
  int prix[2][2] = {
      {11, 12},
      {13, 14}};
  affichage(prix);
  return 0;
}

3.4. Le passage de paramètres

2.2. Passage par référence: un tableau

void affichage( int (*tableau)[2] ) {
  for ( int i = 0; i < 2; i++) {
    for ( int j = 0; j < 2; j++) {
     printf("%d\n",  tableau[i][j]);
    }
  }
}

int main() {
  int prix[2][2] = {
      {11, 12},
      {13, 14}};
  affichage(prix);
  return 0;
}

3.4. Le passage de paramètres

2.2. Passage par référence: un tableau

void affichage( int **tableau, int lignes, int colonnes ) {
  for ( int i = 0; i < lignes; i++) {
    for ( int j = 0; j < colonnes; j++) {
     printf("%d\n",  tableau[i][j]);
    }
  }
}

int main() {
  int **prix, lignes, colonnes;
  ....
  affichage(prix, lignes, colonnes);
  return 0;
}

3.4. Le passage de paramètres

un tableau à deux indices

3.4. Le passage de paramètres

Passage par référence: un tableau

int main() {
  int **tableau, lignes = 2, colonnes = 10;
  tableau = calloc(sizeof(int *), lignes);
  for ( int i = 0; i < lignes; i++) {
   tableau[i] = calloc(sizeof(int), colonnes);
  }
  for ( int i = 0; i < lignes; i++) {
    for ( int j = 0; j < colonnes; j++) {
       tableau[i][j] = i+j;
    }
  }
...

3.4. Le passage de paramètres

Passage par référence: un tableau

...
  affichage(tableau, lignes, colonnes);
  for ( int i = 0; i < lignes; i++) {
   free(tableau[i]);
  }
  free(tableau);
  return 0;
}

3.5. Préprocesseur

cercle.c

#define PI 3.14159

float area( float radius) {
 return(PI * radius * radius);
}

3.5. Préprocesseur

Prototype (defs.h)

#define PI 3.1415926535

cercle.c

#include "defs.h"
#ifndef PI // Si PI n'est pas défini
#define PI 3.14159
#endif

float area( float radius) {
 return(PI * radius * radius);
}

Remarque 1: PI n'est pas une variable
Remarque 2: Utilisez l'option gcc -E pour comprendre l'objectif d'un préprocesseur

3.5. Préprocesseur

Prototype (defs.h)

Erreur: PI n'est pas une variable

#include "defs.h"
#ifndef PI
#define PI 3.14159
#endif

float area( float radius) {
 PI = 3.14;
 return(PI * radius * radius);
}

Erreur (compilation)

Error: lvalue required as left operand of assignment
PI = 3.15;
   ^

3.5. Préprocesseur

operators.h

int add( int, int);

L'utilisation

#include "operators.h" // en-têtes(headers)

#include "operators.h" // pas d'erreurs

3.5. Préprocesseur

operators.h

int num = 20;

L'utilisation

#include "operators.h" // en-têtes(headers)

#include "operators.h" // erreur

$ gcc operator.c
note: previous definition of ‘num’ was here
int num=20;

3.5. Préprocesseur

operators.h (bonne pratique)

#ifndef __OPERATORS_H__
#define __OPERATORS_H__

int num = 20;
int add( int, int);

#endif //__OPERATORS_H__

L'utilisation

#include "operators.h" // en-têtes(headers)

#include "operators.h" // 2eme fois, mais pas d'erreurs

3.5. Préprocesseur

#ifndef PI
#define PI 3.14159
#endif

#ifndef square
#define square(value) value * value
#endif

float area( float radius) {
 return(PI * square(radius));
}

Remarque: Il'n y a pas d'espace entre square et (

3.6. Alignement en mémoire

Source: https://commons.wikimedia.org/wiki/File:AdditiveColorMixiing.svg

3.6. Alignement en mémoire

struct couleur1{
 unsigned char rouge;
 unsigned char vert;
 unsigned char bleu;
 unsigned int count;
};
struct couleur2{
 unsigned char rouge;
 unsigned int count;
 unsigned char vert;
 unsigned char bleu;
};
 printf( "size- couleur1: %lu, couleur2: %lu\n",
  sizeof( struct couleur1), sizeof( struct couleur2));

Question: Quel est l'affichage de ce programme?

3.6. Alignement en mémoire

Alignement d'un octet

couleur1
couleur2

3.6. Alignement en mémoire

Alignement de 4 octets

couleur1
couleur2

3.6. Alignement en mémoire

Alignement en utilisant gcc

3.6. Alignement en mémoire

En utilisant gcc

#pragma pack(push)
#pragma pack(1) //alignement d'un octet
struct couleur3{
 unsigned char rouge;
 unsigned char vert;
 unsigned char bleu;
 unsigned int count;
};
#pragma pack(pop)

 printf( "%lu\n", sizeof(struct couleur3));

Remarque: L'affichage de ce programme: 7

3.6. Alignement en mémoire

struct couleur4{ //alignement de 4 octets
 unsigned char rouge;
 unsigned char vert;
 unsigned char bleu;
 unsigned char _pad;
 unsigned int count;
};
struct couleur5{ //alignement de 4 octets
 unsigned char rouge;
 unsigned char _pad1[3];
 unsigned int count;
 unsigned char vert;
 unsigned char bleu;
 unsigned char _pad2[2];
};

Remarque: Utilisez l'option gcc -Wpadded pour savoir si une structure nécessite du padding our être alignée

3.7. Les structures et les pointeurs

struct couleur{
 unsigned char rouge;
 unsigned char vert;
 unsigned char bleu;
 unsigned int count;
};
int main() {
 struct couleur c1;
 struct couleur *scptr = &c1;
 c1.bleu = 0xff;
 scptr->bleu = 0x01;
 printf( "c1.bleu: %hhx\n", c1.bleu); //0x01
 (*scptr).bleu = 0x22;
 printf( "c1.bleu: %hhx\n", c1.bleu); //0x22
}
Source: https://commons.wikimedia.org/wiki/File:AdditiveColorMixiing.svg

3.7. Les structures et les pointeurs

 struct couleur *scptr = &c1;

Les notations équivalents

(*scptr).bleu scptr->bleu

3.7. Les structures et les pointeurs

struct couleur{
 unsigned char rouge;
 unsigned char vert;
 unsigned char bleu;
 unsigned int count;
};
void change( struct couleur *c) {
 c->bleu = 0x01;
}
int main() {
 struct couleur c1;
 c1.bleu = 0xff;
 change(&c1);
 printf( "c1.bleu: %hhx\n", c1.bleu); //0x01
}

3.7. Les structures et les pointeurs

struct couleur{
 unsigned char rouge;
 unsigned char vert;
 unsigned char bleu;
 unsigned int count;
};
void nochange( struct couleur c) {
 c.bleu = 0x03;
}
int main() {
 struct couleur c1;
 c1.bleu = 0xff;
 nochange(c1);
 printf( "c1.bleu: %hhx\n", c1.bleu); //0xff
}

3.7. Les structures et les pointeurs

Une liste de couleurs simplement chaînée

3.7. Les structures et les pointeurs

Une liste de couleurs simplement chaînée

struct couleur{
 unsigned char rouge;
 unsigned char vert;
 unsigned char bleu;
 unsigned int count;
 struct couleur *next;
};

3.7. Les structures et les pointeurs

Une liste de couleurs simplement chaînée

int main() {
 struct couleur first, c1, c2;
 struct couleur *cptr;
 first.next = &c1;
 c1.next = &c2;
 c2.next = NULL;
 cptr = &first;

 while(cptr != NULL) { //navigation
  printf( "cptr->bleu: %hhx\n", cptr->bleu);
  cptr = cptr->next; //couleur suivante
 }
}

3.7. Les structures et les pointeurs

Une liste d'entiers simplement chaînée

3.7. Les structures et les pointeurs

Une liste d'entiers simplement chaînée

struct element{
 unsigned int numero;
 struct element *suivant;
};

// insertion d'un élement dans une liste
void insertion(struct element*, int);

// parcours de la liste
void parcours(struct element *);

3.7. Les structures et les pointeurs

La saisie d'entiers par l'utilisateur

int main() {
 struct element premier;
 premier.suivant = NULL;
 while(1) {
   int num;
   char strnum[50];
   fgets(strnum, sizeof(strnum), stdin);
   if(strcmp(strnum, "FIN\n") == 0) {
     break;
   }

   sscanf(strnum, "%d\n", &num);
   insertion(&premier, num);
 }
 parcours(&premier);
}

3.7. Les structures et les pointeurs

Une liste d'entiers simplement chaînée: insertion

3.7. Les structures et les pointeurs

Insertion d'un élément dans une liste simplement chaînée

void insertion(struct element *premier, int num) {
  struct element *nouveau;
  nouveau = malloc(sizeof(*nouveau));
  nouveau->num = num;
  nouveau->suivant = premier->suivant;
  premier->suivant = nouveau;
}
 

3.7. Les structures et les pointeurs

Une liste d'entiers simplement chaînée: parcours

3.7. Les structures et les pointeurs

Parcours d'une liste simplement chaînée

void parcours(struct element *premier) {
   struct element *elem = premier;
   while(elem != NULL) {
   printf("%d\n", elem->num);
   elem = elem->suivant;
  }
 }

3.7. Les structures et les pointeurs

Une liste de couleurs doublement chaînée

3.7. Les structures et les pointeurs

Une liste de couleurs doublement chaînée

struct couleur{
 unsigned char rouge;
 unsigned char vert;
 unsigned char bleu;
 unsigned int count;
 struct couleur *next;
 struct couleur *prev;
};

3.7. Les structures et les pointeurs

int main() {
 struct couleur first, c1, c2, last;
 struct couleur *cptr = &last;

 first.next = &c1;
 first.prev = NULL;
 last.next = NULL;
 last.prev = &c2;
 c1.next = &c2;
 c1.prev = &first;
 c2.next = &last;
 c2.prev = &c1;

 while(cptr != &first) { //navigation
  printf( "cptr->bleu: %hhx\n", cptr->bleu);
  cptr = cptr->prev; //couleur précédente
 }
}

3.7. Les structures et les pointeurs

Une liste d'entiers simplement chaînée

3.7. Les structures et les pointeurs

Insertion d'un élément et parcours d une liste doublement chaînée

 struct element {
   int num;
   struct element *suivant;
   struct element *precedent;
 };
 
 struct liste {
   struct element premier;
   struct element dernier;
 };
 
 void insertion_debut(struct liste *, struct element *);
 void insertion_fin(struct liste *, struct element *);
 void parcourir_debut(struct liste *);
 void parcourir_fin(struct liste *);

3.7. Les structures et les pointeurs

Une liste de couleurs doublement chaînée: insertion

3.7. Les structures et les pointeurs

Une liste d'entiers doublement chaînée

 void insertion_debut(struct liste *liste,
   struct element *nouveau) {
  nouveau->suivant = liste->premier.suivant;
  nouveau->precedent = &liste->premier;
  liste->premier.suivant->precedent = nouveau;
  liste->premier.suivant = nouveau;
 }
 

3.7. Les structures et les pointeurs

Une liste de couleurs doublement chaînée: insertion

3.7. Les structures et les pointeurs

Une liste d'entiers doublement chaînée

 void insertion_fin(struct liste *liste,
    struct element *nouveau) {
  nouveau->suivant = &liste->dernier;
  nouveau->precedent = liste->dernier.precedent;
  liste->dernier.precedent->suivant = nouveau;
  liste->dernier.precedent = nouveau;
 }

3.7. Les structures et les pointeurs

Une liste d'entiers doublement chaînée

 void parcourir_debut(struct liste *liste) {
  struct element *elem = liste->premier.suivant;
  while(elem != &liste->dernier) {
   printf("%d\n", elem->num);
   elem = elem->suivant;
  }
 }
 

3.7. Les structures et les pointeurs

Une liste d'entiers doublement chaînée

 
 void parcourir_fin(struct liste *liste) {
  struct element *elem = liste->dernier.precedent;
  while(elem != &liste->premier) {
   printf("%d\n", elem->num);
   elem = elem->precedent;
  }
 }

3.7. Les structures et les pointeurs

La saisie d'entiers par l'utilisateur

 int main() {
  struct liste liste;
  liste.premier.suivant = &liste.dernier;
  liste.dernier.precedent = &liste.premier;
  liste.premier.precedent = NULL;
  liste.dernier.suivant = NULL;
 

3.7. Les structures et les pointeurs

La saisie d'entiers par l'utilisateur

  while (1) {
   char strnum[50];
   struct element *elem = malloc(sizeof(*elem));
   fgets(strnum, sizeof(strnum), stdin);
   if(strcmp(strnum, "FIN\n") == 0) {
    break;
   }
 
   sscanf(strnum, "%d\n", &elem->num);
   insertion_fin(&liste, elem);
  }
 
  parcourir_debut(&liste);
  parcourir_fin(&liste);
 }

3.7. Les fonctions et les pointeurs

int add( int a, int b ) {
 return a + b;
}

int subtract( int a, int b ) {
 return a - b;
}

3.7. Les fonctions et les pointeurs

int main() {
 int (*func)(int, int); //pointeur de function
 char op = '-';
 int num1 = 20, num2 = 30;

 if (op == '+') {
  func = add;
 }
 else {
  func = subtract;
 }
 printf("value: %d\n",func(20, 30));
}

3.8. Les erreurs: perror

/* Fichier: stats.c
* la taille d'un fichier
* auteur: John Samuel
*/

#include <stdio.h> // en-têtes(headers)
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char ** argv) {
 struct stat sf;
 stat ("./stats.c", &sf);
 printf("Taille: %ld octets", sf.st_size);
 return 0;
}

3.8. Les erreurs: perror

#include <stdio.h> // en-têtes(headers)
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char ** argv) {
 struct stat sf;
 int status;

 status = stat (argv[1], &sf);
 if (status == -1) {
  perror("Stats");
  return(EXIT_FAILURE);
 }
 printf("Taille: %ld octets", sf.st_size);
 return 0;
}

3.8. Les erreurs: perror

La compilation

$ gcc -o stats stats.c

L'exécution

$./stats stats.c
Taille: ... octets
$ echo $?
0

3.8. Les erreurs: perror

La compilation

$ gcc -o stats stats.c

L'exécution

$ ./stats nostats
Stats: No such file or directory
$ echo $?
1

3.9. Répertoire (dossier)

#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char **argv) {
 if (argc < 2) {
  printf("Usage: readdir path\n");
  return(EXIT_FAILURE);
 }

 DIR *dirp = opendir(argv[1]);

 if (dirp == NULL) {
  perror("opendir");
  return(EXIT_FAILURE);
 }

3.9. Répertoire (dossier)

 struct dirent * ent;
 while(1) {
  ent = readdir(dirp);
  if (ent == NULL) {
   break;
  }
  printf("%s\n", ent->d_name);
 }

 closedir(dirp);

 return(0);
}

3.10. Réseau: Architecture client-serveur

3.10. Réseau: Architecture client-serveur

Client

3.10. Réseau: Architecture client-serveur

Client

#define PORT 8089

int main() {
 int socketfd;
 int bind_status;
 struct sockaddr_in server_addr, client_addr;

 /*
  * Création d'un socket
  * AF_INET: Protocoles Internet IPv4
  * SOCK_STREAM: flux d'octets bidirectionnels, basés sur la connexion
  */

 socketfd = socket(AF_INET, SOCK_STREAM, 0);
 if ( socketfd < 0 ) {
  perror("Impossible d'ouvrir un socket");
  return -1;
 }

3.10. Réseau: Architecture client-serveur

Client

 // détails de l'adresse du serveur
 memset(&server_addr, 0, sizeof(server_addr));
 server_addr.sin_family = AF_INET;
 server_addr.sin_port = htons(PORT);
 server_addr.sin_addr.s_addr = INADDR_ANY;

 //Se connecter au serveur
 int connect_status = connect(socketfd, (struct sockaddr *)
   &server_addr, sizeof(server_addr));
 if ( connect_status < 0 ) {
  perror("Impossible de se connecter au serveur");
  return -1;
 }

3.10. Réseau: Architecture client-serveur

Serveur

3.10. Réseau: Architecture client-serveur

Serveur

int main() {

 int socketfd;
 int bind_status;

 struct sockaddr_in server_addr, client_addr;

 /*
  * Création d'un socket
  * AF_INET: Protocoles Internet IPv4
  * SOCK_STREAM: flux d'octets bidirectionnels, basés sur la connexion
  */

 socketfd = socket(AF_INET, SOCK_STREAM, 0);
 if ( socketfd < 0 ) {
  perror("Impossible d'ouvrir un socket");
  return -1;
 }

3.10. Réseau: Architecture client-serveur

Serveur

 int option = 1;
 setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR,
  &option, sizeof(option));

 // détails de l'adresse du serveur
 memset(&server_addr, 0, sizeof(server_addr));
 server_addr.sin_family = AF_INET;
 server_addr.sin_port = htons(PORT);
 server_addr.sin_addr.s_addr = INADDR_ANY;

 bind_status = bind(socketfd, (struct sockaddr *)
   &server_addr, sizeof(server_addr));
 if (bind_status < 0 ) {
  perror("Impossible de se lier à un socket");
  return -1;
 }

 // Commencez à écouter le socket
 listen(socketfd, 10);

3.10. Réseau: Architecture client-serveur

 char data[1024];

 int client_addr_len = sizeof(client_addr);
 int client_socket_fd = accept(socketfd,
   (struct sockaddr *) &client_addr, &client_addr_len);
 if(client_socket_fd < 0 ) {
  perror("Impossible d'accepter les demandes des clients");
  return -1;
 }

3.11. La chaine de compilation

6 étapes de la chaine de compilation

3.11. La chaine de compilation

1. Préprocesseur

cercle.c

#ifndef PI
#define PI 3.14159
#endif

float area( float radius) {
 return(PI * radius * radius);
}

3.11. La chaine de compilation

1. Préprocesseur

$ gcc -E cercle.c # 1 "cercle.c"
# 1 ""
# 1 ""
# 31 ""
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "" 2
# 1 "cercle.c"

float area(float radius) {
return(3.14 * radius * radius);
}

3.11. La chaine de compilation

2. Langage intermédiaire

$ gcc -v bonjour.c # les étapes importantes
$ gcc -save-temps -v bonjour.c # les fichiers *.i, *.s
$ gcc -fdump-tree-all bonjour.c
$ gcc -fdump-rtl-all bonjour.c

3.11. La chaine de compilation

2. Langage intermédiaire

$ gcc -fdump-tree-all -c cercle.c
$ cat cercle.c.005t.gimple
area (float radius)
{
float D.1914;

_1 = (double) radius;
_2 = _1 * 3.140000000000000124344978758017532527446746826171875e+0;
_3 = (double) radius;
_4 = _2 * _3;
D.1914 = (float) _4;
return D.1914;
}

3.11. La chaine de compilation

3. Optimisation de code

$ gcc -O2 bonjour.c
$ gcc -O3 bonjour.c

Remarque: Autres optimisations: -O1 -O2 -O3 -Os -Ofast -Og

3.11. La chaine de compilation

4. Génération de code natif

$ gcc -S bonjour.c
$ cat bonjour.s

3.11. La chaine de compilation

4. Génération de code natif et l'optimisation de code

int main() {
  int num = 2 + 3;
  return(0);
}

Compilation (Pas d'optimisations)

$ gcc -O0 -S add.c

add.s

main:
.LFB0:
  .cfi_startproc
  pushq %rbp
  .cfi_def_cfa_offset 16
  .cfi_offset 6, -16
  movq %rsp, %rbp
  .cfi_def_cfa_register 6
  movl $5, -4(%rbp)
  movl $0, %eax
  popq %rbp
  .cfi_def_cfa 7, 8
  ret
  .cfi_endproc

3.11. La chaine de compilation

4. Génération de code natif et l'optimisation de code

int main() {
  int num = 2 + 3;
  return(0);
}

Compilation (optimisation: 2)

$ gcc -O2 -S add.c

add.s

main:
.LFB0:
  .cfi_startproc
  xorl %eax, %eax
  ret
  .cfi_endproc

3.11. La chaine de compilation

4. Génération de code

sur une machine d'architecture 64 bits

$ gcc bonjour.c
$ file a.out
 a.out: ELF 64-bit LSB shared object, x86-64

3.11. La chaine de compilation

4. Génération de code

sur une machine d'architecture 64 bits

$ gcc -march=i686 -m32 bonjour.c
$ gcc -S -march=i686 -m32 bonjour.c
$ file ./a.out
 ./a.out: ELF 32-bit LSB shared object, Intel 80386

3.11. La chaine de compilation

5. Code objet

$ gcc -c client.c
$ gcc -c color.c
$ gcc -o color color.o client.o

3.11. La chaine de compilation

5. Code objet (Modifications et recompilation)

$ gcc -c client.c
$ gcc -c color.c
$ gcc -o client client.o color.o
$ vim client.c # Modification du fichier
$ gcc -c client.c
$ gcc -c client.o color.o
$ vim client.c # Modification du fichier
$ gcc -c client.c
$ gcc -o client client.o color.o

3.12. Makefile

Makefile

Makefile et make permettent de créer facilement un exécutable à partir du code source. Il prend en considération la dernière heure de modification des fichiers pour décider de l'exécution ou non d'une ou plusieurs commandes.

$ cat Makefile
client: client.c color.c # création de l'exécutable client
<TAB>gcc -o client client.c color.c

3.12. Makefile

Makefile

$ make
gcc -o client client.c color.c

3.12. Makefile

Makefile

$ cat Makefile
client: client.o color.o # création de l'exécutable client
 gcc -o client client.o color.o

client.o: client.c client.h # compilation
 gcc -c client.c

color.o: color.c color.h # compilation
 gcc -c color.c

3.12. Makefile

Makefile

$ cat Makefile
CC ?= gcc

CFLAGS ?= -Wall -Wextra -g

COBJS ?= client.o color.o
SOBJS ?= server.o color.o

.SUFFIXES: .c .o

SERVER = server
CLIENT = client

3.12. Makefile

Makefile

all: $(SERVER) $(CLIENT) #création des exécutables

$(SERVER): $(SOBJS) # création de l'exécutable server
    $(CC) -o $(SERVER) $(SOBJS)

$(CLIENT): $(COBJS) # création de l'exécutable client
    $(CC) -o $(CLIENT) $(COBJS)

.c.o: # Compilation de tous les fichiers
    $(CC) -c $*.c

3.12. Makefile

Exécution d'un Makefile

$ vim server.c # Modification du fichier
$ vim client.c # Modification du fichier
$ vim color.c # Modification du fichier
$ make # Compilation de tous les fichiers et création d'un exécutable.
$ vim color.c # Modification du fichier
$ make # Compilation d'un seul fichier (color.c) et création d'un exécutable.
$ make # Ni compilation ni création d'un nouveau exécutable car aucun fichier n'a été modifié

3. Algorithmes et C: Références

Références

Crédits d'images