Page content

Bibliothèques C

Le programme “./prime”

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <stdbool.h>
#include <errno.h>
#include <string.h>

int main(int argc, char** argv) {
    if (argc < 2) {
        fprintf(stderr, "Vous devez fournir la borne supérieure\n");
        return -1;
    }
    char* endptr;
    long int argument = strtol(argv[1], &endptr, 0); //strtol pour convertir de String vers Integer
    if (*argv[1] == '\0' || *endptr != '\0' || argument <= 0) {
        fprintf(stderr, "La borne fournie doit être un entier supérieur à 0\n");
        return -1;
    }
    long int racine_i, j, i ;
    size_t cap = 8;
    long int* primes = malloc(cap * sizeof(long int)); // Tableau de nombres premiers trouvés (à allouer dans le tas et réallouer)
    if (primes == NULL) {
        perror("Allocation");
        return 1;
    }
    size_t nb = 0 , k;
    bool prime ;
    for (i=2; i<=argument; i++) {
        prime = true ;
        racine_i = (long int)sqrt((double)i) ;
        for (k=0; k<nb; k++) {
            j = primes[k] ;
            if ( j > racine_i ) {
                break ; // on trouvera plus de diviseur, inutile de continuer de chercher
            }
            if (i%j == 0) {
                prime = false ; // c'est divisible, donc pas premier
                break ;
            }
        }
        if (prime) {
            // on enregistre et on passe au nombre suivant
            primes[nb] = i ;
            nb++ ;
            if(nb > cap){
                cap *= 2;
                primes = realloc( primes, sizeof(long int) * cap);
                if(primes == NULL){
                    fprintf(stderr, "La valeur de errno: %d\nInterprétation: %s",errno, strerror(errno)) ;
                    return 1;
                }
            }
        }
    }
    printf("Nombre de nombres premiers trouvés : %ld\n", nb) ;
    free(primes);
    //Affichage des nombres premiers trouvés
    /*printf("Affichage des nombres premiers trouvés : \n") ;
    for(int long h = 0 ; h!=nb ; h++){
        printf("%ld  ", primes[h] ) ;
    }
    printf("\n") ;*/
    return 0 ;

}
  • Ça permet de mentionner à l’éditeur de lien que nous allons faire appel à la bibliothèque maths. Pour plus d’information man 3 sqrt
  • ldd fichier permet de voir où sont les bibliothèques d’un exécutable. Les bibliothèques avec l’extension .a sont des bibliothèques statiques, et les bibliothèques avec l’extension .so sont des bibliothèques dynamiques. ldd ./prime
  • La fonction sqrt() n’est pas un appel système, car elle ne nécessite pas le mode noyau pour s’exécuter. Pour approcher la racine carrée d’un nombre, il y a plusieurs méthodes : méthode de Newton, méthode de dichotomie, …etc, et souvent sqrt est fourni par les processeurs (avec leurs propres techniques d’approximation).

Remarque. Les appels système sont liés à un système d’exploitation précis. Il y a plusieurs systèmes d’exploitation et ils viennent en plusieurs versions. Les standards comme POSIX ne sont pas toujours implémentés et peuvent aussi être étendus. De manière générale, pour savoir si une fonction est un appel système, faut intéroger l’OS en question. Sous Linux man syscalls va lister tous les appels système supportés.

Strace

Babel

Programme “Hello, World!” en C

#include <stdio.h>

int main(){
	printf("Hello, World!\n");
	return 0;
}
  • l’appel système write utilisé pour afficher le Hello, World!.
strace -e trace=write ./Hello_World_c

Programme “Hello, World!” en C++

#include <iostream>

int main(){
    std::cout << "Hello, world!\n";
    return 0;
}
  • l’appel système write utilisé pour afficher le Hello, World!.
strace -e trace=write ./Hello_World_cpp

Programme “Hello, World!” en Bash

#!/bin/bash

echo "Hello, World!"
  • l’appel système write utilisé pour afficher le Hello, World!.
strace -e trace=write ./Hello_World_bash.sh

Programme “Hello, World!” en Python

print("Hello, World!")
  • l’appel système write utilisé pour afficher le Hello, World!.
strace -e trace=write python ./Hello_World_python.py
  • Conclusion : il y a nécessairement des appels système effectués pour réussir à afficher Hello, World!, il n’y a pas de passe-droits ou de contournement possible, peu importe le langage de programmation utilisé.

Tubes et redirections

  1. strace ./Hello_World_c > fichier
  2. strace ./Hello_World_c | cowsay
  • On remarque que ni la redirection ni l’utilisation des tubes n’impactent l’utilisation des appels système par les programmes.

Variété

strace -tf sleep 5
  • strace -c sleep 5 affiche 32 appels système pour sleep 5
  • sleep 5 ne fait ni calcul ni entrées-sorties
  • Les appels système les plus utilisés sont : “mmap” et “close”
strace -tf ./prime 100
  • strace -c ./prime 100 affiche 37 appels système pour ./prime
  • ./prime fait plus de calcul qu’entrées-sorties
  • Les appels système les plus utilisés sont : “mmap” et “mprotect”
strace -tf find /usr/lib
  • strace -c find /usr/lib affiche 77356 appels système pour find /usr/lib
  • find /usr/lib fait plus d’entrées-sorties que de calcul
  • Les appels système les plus utilisés sont : “write”, “fcntl” et “close”
strace -tf xeyes
  • strace -c xeyes affiche 2947 appels système pour xeyes
  • xeyes fait plus d’entrées-sorties que de calcul
  • Les appels système les plus utilisés sont : “recvmsg” et “poll”
strace -tf mpv mamusique.mp3
  • strace -c mpv mamusique.mp3 affiche 7763 appels système pour mpv mamusique.mp3 pour une durée de 15 secondes
  • mpv mamusique.mp3 fait plus de calcul que d’entrées-sorties
  • Les appels système les plus utilisés sont : “futex” et “getpid”

Conclusion

Les programmes interactifs qui utilisent beaucoup d’entrées-sorties font beaucoup d’appels systèmes contrairement au programme prime qui fait beaucoup de calcul et utilise peu d’appels système, et aussi la commande sleep qui ne fait ni calcul ni entrées-sorties.