Il linguaggio C: cenni generali

Come qualunque linguaggio, anche il linguaggio C si compone di parole e regole; queste ultime costituiscono la portante grammaticale e sintattica che consente di aggregare le prime per formare frasi di senso compiuto.

Come qualsiasi linguaggio di programmazione, inoltre, il linguaggio C rappresenta in qualche modo un compromesso tra l'intelligenza umana e l'intrinseca stupidità della macchina. Esso costituisce il mezzo tramite il quale il programmatore "spiega" alla macchina come effettuare determinate operazioni.

Naturalmente (si perdoni l'ovvietà) la macchina non è in grado di capire direttamente il linguaggio C: essa è troppo stupida per poterlo fare, e d'altra parte il C è direttamente leggibile e comprensibile dagli esseri umani; troppo distante, quindi, dalla logica binaria, l'unica che abbia senso per un calcolatore.

Perché la macchina possa eseguire un programma scritto in C, anche il più banale, occorre rielaborarlo fino a ridurlo ad un insieme di valori esprimibili in codice binario: diciamo, per capirci, che questi rappresentano la traduzione in linguaggio macchina di quanto il programmatore ha espresso in linguaggio C, il quale non è altro che un "sottolinguaggio" della lingua parlata dal programmatore stesso, o, in altre parole, un sottoinsieme di quella.

In effetti, l'utilizzo di sottoinsiemi della lingua parlata per scrivere programmi deriva dall'esigenza di semplificare la traduzione del programma nell'unica forma comprensibile alla macchina (il binario, appunto): lo scopo è eliminare a priori le possibili ambiguità, le scorrettezze grammaticali e, in generale, tutti quei "punti oscuri" dei discorsi in lingua naturale che sono solitamente risolti dall'essere umano mediante un processo di interpretazione o di deduzione dei significati da conoscenze che non sono direttamente reperibili nel discorso stesso ma derivano dall'esperienza e dalla capacità di inventare. La macchina non impara e non inventa.

Sebbene quanto detto valga, evidentemente, per tutti i linguaggi di programmazione, va sottolineato che il C ha caratteristiche proprie, che ne fanno, in qualche modo, un linguaggio particolare.

Innanzitutto esso dispone di un insieme limitatissimo di istruzioni. E' dunque un linguaggio intrinsecamente povero, ma può essere facilmente ed efficacemente arricchito: chiunque può aggiungere nuove istruzioni (o meglio, funzioni) alla strumentazione che accompagna il linguaggio. In pratica si possono coniare neologismi e creare dei vocabolari aggiuntivi a quello proprio del linguaggio, che potranno essere utilizzati all'occorrenza. Di fatto, in C, anche la gestione dello I/O (Input/Output) è implementata così. Un gran numero di funzioni esterne al linguaggio è ormai considerato universalmente parte del linguaggio stesso ed accompagna sempre il compilatore, nonostante, dal punto di vista strettamente tecnico, questo sia comunque in grado di riconoscere solo un piccolo numero di istruzioni intrinseche.

Tutto ciò si traduce anche in una relativa semplicità funzionale del compilatore: sono quindi molti gli ambienti per i quali è stato sviluppato un compilatore dedicato. Essendo la maggior parte del linguaggio esterna al compilatore, è possibile riutilizzarla semplicemente facendo "rimasticare" i file sorgenti delle funzioni (e sono sorgenti C) al compilatore[1] con il quale dovranno essere associati. In questo sta la cosiddetta portabilità del C, cioè la possibilità di utilizzare gli stessi sorgenti in ambienti diversi, semplicemente ricompilandoli.

Un'altra caratteristica del C è la scarsità di regole sintattiche. Il programmatore ha molta libertà di espressione, e può scrivere programmi che riflettono ampiamente il suo personalissimo stile, il suo modo di risolvere i problemi, il suo tipo di approccio all'algoritmo. Ciò ha senz'altro riflessi positivi sull'efficienza del programma, ma può essere causa di difficoltà talora insuperabili, ad esempio nei successivi interventi sul sorgente a scopo di manutenzione o di studio, quando lo stile del programmatore sia eccessivamente criptico. La regola forse più importante che il programmatore C deve seguire, nonostante non faccia parte del linguaggio, è la cosiddetta regola "KISS" (Keep It Simple, Stupid).

Infine, il C mette a disposizione concetti e strumenti che consentono un'interazione "di basso livello" con la macchina e con le sue risorse. Per "basso livello" non si intende qualcosa di poco valore, ma una piccola distanza dalla logica binaria della macchina stessa. Ne deriva la possibilità di sfruttare a fondo, e con notevole efficienza, tutta la potenza dell'elaboratore. Non a caso il C è nato come linguaggio orientato alla scrittura di sistemi operativi[2]; tuttavia la possibilità di estenderlo mediante librerie di funzioni ha fatto sì che, nel tempo, esso divenisse linguaggio di punta anche nella realizzazione di programmi applicativi, per i quali ne erano tradizionalmente usati altri[3].

L'evoluzione più recente del C è rappresentata dal C++, il quale è, in pratica, un "superset" del C stesso, del quale riconosce ed ammette tutti i costrutti sintattici, affiancandovi le proprie estensioni: queste consentono al programmatore di definire delle entità composte di dati e del codice eseguibile atto alla loro manipolazione. Dette entità vengono così trattate, a livello logico, come se fossero tipi di dato intrinseci al linguaggio e consentono pertanto di descrivere la realtà su cui il programma opera in termini di linguaggio fondamentale: è la cosiddetta programmazione ad oggetti. Che il C++ sia un'estensione del C (e non un nuovo linguaggio) è dimostrato dal fatto che gli arricchimenti sintattici sono tutti implementati a livello di  preprocessore[4]; in altre parole, ogni sorgente C++ viene ridotto a sorgente C dal preprocessore e poi masticato da un normale compilatore C.

I programmi eseguibili risultanti sono efficienti e compatti in quanto il compilatore traduce ogni istruzione C in un numero limitato di istruzioni macchina (al limite una sola): solo l'Assembler è più efficiente (ma rende la vita del programmatore assai più dura).


OK, andiamo avanti a leggere il libro...

Non ci ho capito niente! Ricominciamo...