Corso C avanzato su Raspberry PI: Creiamo le nostre librerie

La quinta lezione del corso avanzato sul linguaggio C verte sulla creazione di librerie, contenenti le proprie funzioni da richiamare all'occorrenza, senza doverle riscrivere da capo. Con tale possibilità è possibile modularizzare al massimo la codifica e consentire ad altre persone di utilizzare le proprie librerie anche senza la necessità di visionare praticamente il codice.

Una scatola chiusa

Una libreria è un insieme di funzioni scritte, in questo caso, in linguaggio C. Esse sono utilizzate quando delle particolari funzioni sono richiamate spesso nei propri programmi. Il linguaggio C dispone già di esse per gli usi più generali, tuttavia il programmatore può crearne in aggiunta, in modo da standardizzare le procedure. In questa maniera egli non si deve più preoccupare più di preparare una determinata procedura o funzione, ma si dedicherà solo al suo utilizzo.

Ovviamente, se la libreria contiene errori o bug, si pone davanti a esso una drammatica situazione che deve cercare di risolvere nel minor tempo possibile, specialmente se le sue applicazioni sono distribuite a un vasto pubblico di utenti.

Programmi e librerie

Creare una libreria è molto differente dal realizzare programmi e software. La libreria, infatti, non contiene intere applicazioni ma semplicemente una o più funzioni che risolvono un determinato problema. Tali funzioni possono anche essere estremamente complesse e più lunghe, in termini di codice, di un normale programma. E' possibile, dunque, distribuire la propria libreria ai programmatori, che la possono utilizzare, sicuramente con tanto vantaggio, per le proprie applicazioni.

Convenzioni

Al fine di mantenere vivo lo standard procedurale occorre seguire alcune regole nell'attribuire il giusto nome a una libreria:

  • il nome di una libreria deve sempre iniziare con "lib";
  • se il nome termina per ".a" vuol dire che si intende utilizzare una libreria statica, come vuole la tradizione. Il codice eseguibile la conterrà per effetto del linking statico;
  • se il nome termina per ".so" vuol dire che si intende utilizzare una libreria dinamica.

Iniziamo subito con i Numeri Primi

Prima di creare una libreria è opportuno verificare che le funzioni che saranno in essa contenute funzionino bene e siano a prova di bomba. Realizziamo, dunque, una funzione che restituisce "1" se il parametro a essa passato è un numero primo, altrimenti "0" se si tratta di un numero composto. La seguente codifica, dunque, non utilizza librerie personalizzate e la procedura di sviluppo e di compilazione è quella standard, ossia programma e funzione contenuti in un unico file sorgente..

#include "stdio.h"
#include "math.h"
int isprime(unsigned long n);
int main() {
   unsigned long  n;
   n=23;
   printf("Primalita' del numero %ld: %d\n",n,isprime(n));
   n=500009;
   printf("Primalita' del numero %ld: %d\n",n,isprime(n));
   n=9876543;
   printf("Primalita' del numero %ld: %d\n",n,isprime(n));
   n=9876553;
   printf("Primalita' del numero %ld: %d\n",n,isprime(n));
   return 0;
}
int isprime(unsigned long n) {
   int test=1;
   unsigned long k,limite;
   limite=sqrt(n);
   for(k=2;k<=limite;k++) 
      if(n % k == 0) {
         test=0;
         break;
      }
   return test;
}

La funzione "isprime" accetta un parametro numerico del quale si vuole conoscere la primalità. Un ciclo con limite pari alla sua radice quadrata cerca di trovare eventuali divisori. Prima della funzione "main()" è riportato il prototipo della funzione "isprime()", in modo da avvertire il compilatore della sua presenza. Come vedremo dopo, con l'utilizzo di una libreria, tale incombenza non sarà più necessaria. A seconda dell'esito, la variabile "test" conterrà il valore "1" per informare che il parametro è un numero primo, oppure "0" per attestare che esso possiede almeno un divisore ed è, pertanto, composto. Per effettuare la compilazione del programma è necessario scrivere il codice in un file di testo, con suffisso finale ".c" e procedere alla compilazione con il seguente comando da terminale:

$ sudo gcc -Wall primi.c -lm

L'opzione -lm avverte il compilatore di cercare le librerie matematiche. L'esecuzione del file binario, invece, è possibile grazie a questo altro comando:

$ sudo ./a.out

che produrrà, a video, la schermata di cui alla figura 1.

Figura 1: esecuzione del programma del test di primalità di un numero

Figura 1: esecuzione del programma del test di primalità di un numero

Creiamo una libreria statica

Constatata la bontà del funzionamento della funzione UDF "isprime()", è possibile passare direttamente alla creazione della libreria, in modo da non dover riscrivere ogni volta, nei nostri sorgenti, il suo codice. Il contenuto della libreria è incluso, a ogni compilazione, anche nel programma eseguibile, per cui non occorre distribuirla all'utente finale. Se si compilano, ad esempio, 50 applicazioni con l'uso della libreria statica, essi conterranno anche la stessa copia di libreria, producendo degli eseguibili molto più pesanti e di grandi dimensioni. Per lo scopo si dovranno seguire i seguenti passi.

Creazione del file header

Si tratta di un file ".h" nel quale sono riportati tutti i prototipi delle funzioni da noi create. Non si dovranno, dunque, ripetere nel sorgente principale.  Il nostro file header, nell'esempio, è stato memorizzato con il nome "primalita.h" e ha il seguente contenuto:

/*
    Libreria per la gestione
       dei Numeri Primi
     by Giovanni Di Maria
*/

int isprime(unsigned long n);
int nextprime(unsigned long n);
int prevprime(unsigned long n);
int isprobabprime(unsigned long n);

Creazione del sorgente di libreria

Si crei, quindi, il file sorgente che conterrà esclusivamente le funzioni UDF da usare nei nostri programmi. Quello dell'esempio si chiama "miefunzioni.c". Il contenuto è il seguente:

#include "math.h"
int isprime(unsigned long n) {
   int test=1;
   unsigned long k,limite;
   limite=sqrt(n);
   for(k=2;k<=limite;k++) 
      if(n % k == 0) {
         test=0;
         break;
      }
   return test;
}

Creazione del sorgente del programma generale

Si tratta del listato generale, che è uguale a quello del precedente capitolo ma senza, ovviamente, la codifica della funzione UDF. Il suo nome è "primi.c" e il suo contenuto è sotto riportato. Come si nota, all'inizio del listato c'è la chiamata al file d'intestazione con il comando di preprocessore #include "primalita.h".

#include "stdio.h"
#include "primalita.h"
int main() {
   unsigned long  n;
   n=23;
   printf("Primalita' del numero %ld: %d\n",n,isprime(n));
   n=500009;
   printf("Primalita' del numero %ld: %d\n",n,isprime(n));
   n=9876543;
   printf("Primalita' del numero %ld: %d\n",n,isprime(n));
   n=9876553;
   printf("Primalita' del numero %ld: %d\n",n,isprime(n));
   return 0;
}

Eseguiamo la sola compilazione del sorgente di libreria

Tale procedura non crea alcun file eseguibile ma "si limita" alla produzione di un file oggetto, utile nelle successive operazioni. A tale scopo si invochi il comando "gcc"  con l'opzione "-c", come evidenziato nel comando di terminale sotto riportato:

$ sudo gcc -Wall -c miefunzioni.c

La compilazione produrrà, in output, il file miefunzioni.o, come visibile anche in figura 2.
[...]

ATTENZIONE: quello che hai appena letto è solo un estratto, l'Articolo Tecnico completo è composto da ben 2226 parole ed è riservato agli abbonati MAKER. Con l'Abbonamento avrai anche accesso a tutti gli altri Articoli Tecnici MAKER e potrai fare il download (PDF) dell'EOS-Book del mese. ABBONATI ORA, è semplice e sicuro.

Abbonati alle riviste di elettronica

Una risposta

  1. Giovanni Di Maria Giovanni Di Maria 27 novembre 2018

Scrivi un commento

EOS-Academy
Abbonati ora!