Introduzione al linguaggio C

lezione
lezione
Introduzione al linguaggio C
Tipo di risorsa Tipo: lezione
Materia di appartenenza Materia: Fondamenti di programmazione in C

Introduzione

modifica
 
Dennis Ritchie(Destra) con Ken Thompson (Sinistra)

Il linguaggio C fu ideato nei Bell Laboratories della AT&T nel 1972 da Dennis Ritchie come evoluzione del linguaggio B usato per la scrittura dei primi sistemi operativi UNIX.

La definizione formale si ha nel 1978 a cura di B.W. Kernighan e D.M. Ritchie. Nel 1983 iniziò il lavoro di definizione di uno standard da parte dell'American National Standards Institute, che rilasciò nel 1990 lo Standard ANSI C (ISO C89).

Il C è tecnicamente un linguaggio di programmazione ad alto livello. Tuttavia, poiché esso mantiene evidenti relazioni semantiche con il linguaggio macchina e l'assembly, risulta molto meno astratto di linguaggi anche affini, come per esempio il Pascal. Per questo motivo, talvolta viene anche identificato con la locuzione (più ambigua) linguaggio di medio livello.

Il C è rinomato per la sua efficienza, e si è imposto come linguaggio di riferimento per la realizzazione di software di sistema su gran parte delle piattaforme hardware moderne. La standardizzazione del linguaggio (da parte dell'ANSI prima e dell'ISO poi) garantisce la portabilità dei programmi scritti in C (standard, spesso detto ANSI C) su qualsiasi piattaforma.

Oltre che per il software di sistema, il C è stato a lungo il linguaggio dominante in tutta una serie di altri domini applicativi caratterizzati da forte enfasi sull'efficienza. Esempi tipici sono le telecomunicazioni, il controllo di processi industriali e il software real-time. Oggi il predominio del C in questi contesti è in parte diminuito a seguito dell'avvento di competitor significativi, primo fra tutti il C++. Tuttavia, il tempo in cui il C si potrà considerare obsoleto appare ancora molto lontano.

Caratteristiche del linguaggio

modifica

Il C è un linguaggio di programmazione relativamente minimalista. La sua semantica utilizza un insieme ristretto di concetti relativamente semplici e vicini al funzionamento dell'hardware dei calcolatori.

Molte istruzioni C sono traducibili direttamente con una singola istruzione di linguaggio macchina (per esempio, gli operatori di autoincremento e autodecremento). Nel linguaggio un ruolo centrale viene svolto dal concetto di puntatore, che viene generalizzato fino a coincidere con l'indirizzamento indiretto, un modo di accedere alla memoria hardware caratteristico di tutte le moderne CPU. Questo rende il C un linguaggio particolarmente efficiente. D'altra parte, rispetto al linguaggio assembly, il C ha in più una struttura logica definita e leggibile, funzioni in stile Pascal e soprattutto il controllo sui tipi (in fase di compilazione), che manca completamente in assembly.

Il C è un linguaggio di programmazione compilato. Ciò vuol dire che è necessario utilizzare un compilatore per trasformare il codice sorgente in un programma eseguibile dal sistema operativo.

La gestione della memoria (a differenza dei linguaggi detti managed in cui quest'ultima viene gestita da un sistema intrinseco al linguaggio) è a carico dello sviluppatore: è il programmatore stesso infatti che alloca determinati blocchi di memoria e si occupa della loro deallocazione.

Inoltre è un linguaggio molto flessibile, con tipi di dati che permettono di costruire strutture dati anche molto complesse.

Il C è un linguaggio procedurale. Ciò vuol dire che non esistono classi, oggetti, eventi, ecc. come per esempio nel C++, Java, Visual Basic, e molti altri linguaggi di più alto livello. L'elemento "portante" dei programmi C è costituito infatti dalle funzioni o procedure.

Gli strumenti necessari

modifica

Come già specificato, per poter eseguire un programma scritto in C, è necessario compilare i sorgenti. Per far questo sono necessari un compilatore e un linker. Ci sono molti compilatori C, molti dei quali gratuiti (per esempio gcc). Per chi volesse utilizzare degli ambienti IDE, durante la scrittura dei programmi sono disponibili Anjuta, per sistemi GNU/Linux e Dev-C++ per Windows. Anche se è consigliabile a chiunque provare a compilare da terminale linux Link diretto per il download del compilatore Dev-C++ Link diretto per il download di Anjuta

La compilazione di un sorgente C è eseguita in 3 fasi:

  • Precompilazione
  • Compilazione
  • Linking

La Precompilazione è eseguita dal precompilatore, che si occupa di includere i files header delle librerie utilizzate, sostituire i valori delle costanti e delle macro definite tramite istruzioni #define, ecc.

La Compilazione è eseguita dal compilatore, che si occupa di trasformare i files sorgenti ottenuti dal precompilatori in files oggetto. Un file oggetto è un file che contiene tutte le informazioni necessare al linker per creare il file eseguibile (tabelle dei simboli, ecc.).

Il Linking è eseguito dal linker, che, come dice il nome stesso, si occupa di unire i vari files oggetti e di collegare tutte le variabili e le funzioni, nonché di collegare all'eseguibile eventuali librerie esterne

Prime basi e Hello World

modifica

I files sorgenti dei programmi scritti in C hanno estensione .c. Per creare un programma, è necessario definire una funzione particolare chiamata main.

 #include <stdio.h>
 
 int main() {
   printf("Hello world!\n");
   return 0;
 }

Questa funzione rappresenta l'entry point del programma, ovvero la funzione chiamata dal sistema operativo all'avvio del programma (vedremo più avanti che in realtà non è proprio questa la prima ma per ora ci basta sapere questo).

Essa restituisce un valore intero che indica al sistema operativo o all'eventuale programma chiamante un codice di uscita, che servirà a capire se il programma ha terminato la propria esecuzione correttamente o con degli errori (di solito 0 si utilizza per indicare l'assenza di errori e tutti gli altri numeri per un errore particolare).

Iniziamo creando un file hello.c. A questo punto è necessario includere un file di intestazione, ovvero un file di libreria in cui sono definite le funzioni standard di input/output del C, di cui parleremo più avanti.

#include <stdio.h>

A questo punto dobbiamo dichiarare la funzione main che, come spiegato prima, ci permetterà di eseguire il programma. Ciò va fatto aggiungendo il seguente codice:

int main () {
    return 0;
}

In questo modo abbiamo dichiarato la funzione main che per la semplicità estrema di questo programma di esempio, conterrà tutto il codice necessario. Se tentassimo di compilare il file prova.c così ottenuto

#include <stdio.h>

int main () {
    return 0;
}

otterremmo un programma perfettamente funzionante ma che non esegue nessuna operazione (provare per credere).

Per creare un primo programma che stampi la classica frase "Hello world!" sul video, utilizzeremo la funzione di libreria printf, di cui parleremo in seguito, in questo modo:

 printf("Hello world!\n");

Questo codice va inserito tra le due parentesi graffe della funzione main in questo modo:

 #include <stdio.h>
 
 int main () {
     printf("Hello world!\n");
     return (0);
 }

La sequenza di caratteri \n, è una sequenza di escape che consente di inserire un carattere new line in una stringa.

Se siete in ambiente GNU/Linux, potete compilare ed eseguire questo file prova.c in questo modo:

$ gcc -o prova prova.c 
$ ./prova
Hello world!
$

dove $ indica la shell. In questo caso è stato utilizzato il compilatore gcc: il parametro -o prova indica che il file eseguibile deve chiamarsi prova; mentre prova.c è il file sorgente che deve essere compilato. In questo esempio viene mostrato anche l'output del programma.