giovedì 31 gennaio 2008

argv[0]

Ho ricevuto spesso da parte di studenti richieste di chiarimento circa il parametro argv[0] di un programma C/Java e la loro differenza. Cerco di riassumere brevemente in questo post il loro significato.


Programmi C

Un programma C ha solitamente il prototipo:

int main( int argc, char** argv )

dove argv rappresenta un array di stringhe (array di array di char) e argc fornisce il numero di stringhe effettivamente passate al programma (ad es. dalla shell). Nel caso del C argv[0] è la stringa contenente il nome del programma stesso.
Ad esempio, se un programma C viene invocato come:

prog_c par1 par2 par3

allora si avrà che

argv[0] = prog_c
argv[1] = par1
argv[2] = par2
argv[3] = par3

argc = 4

La motivazione per la quale argv[0] rappresenta il nome del programma stesso, invece del primo parametro posizionale, deriva dal forte legame fra C e Unix. In Unix è possibile linkare due file residenti sullo stesso file system facendo in modo, tramite gli i-node, che effettivamente i due file creati non esistano, ma ne esista uno solo con due (o più) nomi. Questo significa che prog_c potrebbe essere linkato con un altro nome, ad esempio prog.exe, e potrebbe venir lanciato con entrambi i nodi, poiché di fatto l'i-node punta sempre allo stesso dato fisico su disco.

Il linking di programmi veniva usato in passato per legare programmi con comportamenti simili risparmiando spazio su disco. Ad esempio, il programma cp (copia) e il programma mv (sposta) hanno comportamenti simili. E' quindi possibile creare un solo programma base che implementi un comportamento differente a seconda del nome con il quale è stato invocato. Ecco perché è importante, per un programma C, riuscire a recuperare il nome con il quale è stato invocato.

Programmi Java

Un programma Java ha il seguente prototipo:

public static void main( String argv[] )

con il metodo main che deve essere contenuto in una classe. Anzitutto si noti la similarità con il prototipo C: entrambi accettano un array di stringhe, che sono i parametri passati da riga (ad es. dalla shell). Tuttavia qui è assente il contatore del numero di argomenti, poiché è implicitamente inglobato nell'array argv stesso (argc = argv.length).

A differenza del C, in Java argv[0] rappresenta il primo argomento reale passato al programma. Ad esempio, se si invoca il programma:

java prog_java par1 par2 par3

si avrà che

argv[0] = par1
argv[1] = par2
argv[2] = par3

argv.length = 3
La motivazione di questa differenza dipende da come un programma Java viene invocato. In Java, non si invoca un file eseguibile (come avviene in C), bensì si chiede all'interprete Java di caricare una classe (nell'esempio di cui sopra prog_java) che deve contenere il main. La JVM cerca la classe nel classpath, e la carica. Successivamente ricerca al suo interno il metodo main e lo manda in esecuzione. Siccome in Java una classe pubblica di nome A deve risiedere in un file A.class, e non si può fare altrimenti (la JVM non saprebbe più come trovare le classi), è evidente che non è possibile creare un alias di una classe. Ne consegue che il metodo main ha sempre la certezza di eseguire nella classe nel quale è definito, e quindi l'informazione sul nome del programma (classe) invocato è inutile.

Nessun commento: