Newsgroup: it.comp.lang.c
Titolo: Header file e gcc

Sto provando a scrivere alcuni semplici programmi in modo modulare ma ci
sono un paio di cose che non sono ancora riuscito a capire.
Ho creato tre file: principale.c, funzione.c e funzione.h.
principale.c contiene il main che richiama una funzione di funzione.c.
# include <stdio.h>
# include "funzione.h"
int main()
{
        stampa();
}
funzione.h contiene le dichiarazioni delle funzioni.
void stampa();
funzione.c contiene la funzione stampa.
# include <stdio.h>
void stampa(void)
{
        printf("Hello, world!\n");
}
Se compilo con "gcc principale.c -o principale" ottengo questo errore:
/tmp/ccMNYpRJ.o(.text+0x11): In function `main':
: undefined reference to `stampa'
/tmp/ccMNYpRJ.o(.text+0x16): In function `main':
: undefined reference to `stampa'
/tmp/ccMNYpRJ.o(.text+0x1b): In function `main':
: undefined reference to `stampa'
collect2: ld returned 1 exit status
Se compilo con "gcc principale.c funzione.c" oppure "gcc principale.c
-lm funzione.c" l'eseguibile viene generato correttamente, ma il file
funzione.h risulta inutile, dato che se lo elimino la compilazione
giunge comunque a termine.
Qui il mio dubbio: il file header non dovrebbe servire a definire delle
funzioni visibili all'esterno? Se è così perchè il linker non provvede
automaticamente a generare un eseguibile che contenga tali funzioni
quando compilo il file principale.c?

 wrote in message ev7ogb...@10.0.0.2...


 quando compilo il file principale.c?
e come fa il linker a sapere dove si trova il codice della funzione 
stampa() ?
Ciao,
g.

 quando compilo il file principale.c?
non hai definito le funziooni extern nell'header ed ecco perche' il linker
non riesce a capire cosa deve linkare ...
ciao

 anche il file funzione.c
Ho aggiunto al file principale.c questa riga: 
# include "funzione.c"
oltre a
# include "funzione.h"
che c'era già. Così lo compila senza problemi (anche con l'opzione -Wall
non genera nessun warning). E' un metodo ortodosso o si può fare di
meglio?

 meglio?
non includere mai sorgenti, lasciali compilare a parte avendo cosi' i .o per
ogni file c, facendo cosi' se hai due o piu' file che includono un'altro
sorgente avresti codice ripetuto ed inutile per ogni .o (e potrebbe anche
dare errori il linker sul namedspace)
la soluzione migliore e' nell'header dichiarare le funzioni extern e poi
linkare i due .o lasciando che sia il linker a sistemare le chiamate a
funzione.
ciao

 stampa() ?
E' appunto questa la mia domanda. Man gcc e man ld non mi hanno chiarito
molto le idee.

 molto le idee.
Non occorre dichiarare come extern le funzioni
O compili tutto insieme come hai gia' provato:
gcc principale.c funzione.c -o principale
oppure, se vuoi compilare ogni singolo file puoi solo creare dei file
oggetto, che in seguito andranno linkati.
gcc principale.c -c
gcc funzione.c -c
verranno prodotti i file
principale.o
funzione.o
Questi file sono file compilati, ma a cui mancano solamente i riferimenti a
funzioni eventualmente usate ma non definite all'interno del modulo
corrente. Tali riferimenti verranno risolti nella fase di linking.
Il gcc fa anche da linker, quindi a questo punto puoi fare
gcc principale.o funzione.o -o principale
Per ulteriori dubbi posta pure.
Ciao,
Ema

 Per ulteriori dubbi posta pure.
Grazie mille per la disponibilità.


Non sono aggiornatissimo con i nuovi standard e i compilatori moderni sono
abbastanza furbi.
Evidentemente adesso non e' che gli serva piu' di tanto.
Comunque se compili con l'opzione -Wall
ti dovrebbe dare un warning, che non e' proprio
un errore ma e' indice di qualche cosa che non
e' proprio conforme alla buona programmazione.
Compilare senza warning e' una delle piu' belle soddisfazioni nella vita di
un programmatore... :-)
Ciao,
Ema

 ciao
Non è necessrio specificare "extern" in una dichiarazione di funzione in uno
header, in quanto questo è sempre sottointeso per le funzioni. Il problema in
questo caso è che in linker *non* provvede a cercare automaticamente le
definizioni delle funzioni.

 definizioni delle funzioni.
quindi ha sbagliato a scrivere l'header il giovine ???
ciao


L'OP ha scritto nel suo header:
void stampa();
mentre avrebbe dovuto scrivere:
void stampa(void);
Questo e' l'unico problema: per quanto riguarda le 'undefined references 
to `stampa'' il problema sta nel comando di compilazione. Nel caso del 
gcc il comando esatto e':
gcc -o principale principale.c funzione.c

 definizioni delle funzioni.
C'è un modo per fare si che il linker cerchi le definizioni delle
funzioni? Mi interesserebbe qualcosa di simile a quanto avviene in Java:
se si chiama un metodo contenuto in una classe esterna anche tale classe
viene compilata, senza particolari interventi da parte del
programmatore.

 gcc -o principale principale.c funzione.c
Mi è stato detto più sopra però che compilare in questo modo può
funzionare per header file semplici, ma per cose più complesse potrebbe
non andare bene.
In definitiva vorrei capire qual'è la differenza tra compilare
direttamente in file binari o in file oggetto.

 particolari interventi da parte del programmatore.
Non a livello di linguaggio C. In teoria potrebbe essere il 
compilatore ad occuparsi di questo, ma non conosco compilatori 
che lo facciano.
La cosa che piu' somiglia a cio' che tu cerchi e' l'utility make. 
  Per una descrizione della cosa, vedi Google.

 direttamente in file binari o in file oggetto.
quando il progetto diventa grosso molto probabilmente passerai parametri
diversi di preprocessore per ogni file ... ecco perche' disolito si creano
prima tutti gli oggetti (.o) e poi alla fine li si linka assieme ...
oltre a questo e' un modo per rendere piu' veloce la ricompilazione di
codice in fase di sviluppo, mettiamo il caso che tu modifichi un errore in
un file, dovrei ricompilare solo il suo .o senza ricompilare tutto il
progetto e risparmiando molto tempo ...
poi magari hai comprato in licenza un modulino di funzioni che ti viene dato
solo come uso su file oggetto senza sorgenti ... (un po come alcune
librerie)
altre possibilita' non mi vengono in mente ...
ciao

 mer, 06 ago 2003 alle 18:51 GMT, Enrico 'Trippo' Porreca scrisse:
ah si un'altra possibilita mi viene ... quella cioe' che tu stai sviluppando
in c ma qualche modulo e' sviluppato in un'altro linguaggio (magari in
assembler) se questi linguaggi generano un file oggetto compatibile lo
potrai linkare ed usare nel tuo programma senza grossi problemi (previo
costruzione di header su misura)
ciao

   Per una descrizione della cosa, vedi Google.
Grazie. Ho appena cominciato a leggere un po' di documentazione.

 progetto e risparmiando molto tempo ...
Quindi, detto in soldoni, se ho file1.c file2.c e file3.c prima di tutto
faccio:
gcc -c file1.c file2.c file3.c
e poi linko con:
gcc file1.o file2.o file3.o -o prova
Se trovo un errore in file2.c lo ricompilo con:
gcc -c file2.c
e poi linko nuovamente il tutto:
gcc file1.o file2.o file3.o -o prova
Giusto? Correggetemi se sbaglio.

 ha scritto nel messaggio
news:fr4sgb...@10.0.0.2...

Corretto.
La cosa bella e' che sotto linux esiste uno strumeno chiamato make che ti
automatizza tantissimo tutto questo processo.
Praticamente digitando semplicemente "make" da shell ti ricompila solo i
file modificati e ri-linka il tutto.
Ma qua siamo OT.
Ciao,
Ema

 Ma qua siamo OT.
Grazie a tutti per l'aiuto. Ho appena creato il mio primo makefile!

 Ma qua siamo OT.
oltre all'ot il make e' molto ma molto complesso ... si potrebbe cercare
un'implementazione simile ma piu' modificabile ... disolito per riuscire a
capire con che flag ed altro e' stato creato un make ti tocca spulciarlo per
1000 linee ...
trovo molto piu' facile leggere i file di progetti di visual c in cui estrai
i file da compilare e le flag in 3 secondi netti ... (certo che non portano
dentro tutto il controllo di ricompilazione e varie opzioni di clean install
ecc ...)
tutto questo lo sto dicendo da untilizzatore windows che usa il Dev e
mingw/msys e trovo i file makefile degli scogli assurdi (soprattutto perche'
pensati solo per linux) e trovo invece piu' facile farmi gli import dei
progetti vc.
ciao
ps. scusate per le divagazione ma quando esce un argomento non ci si puo'
astenere da commentarlo

 1000 linee ...
I miei makefile sono molto semplici e non superano in genere le 15/20 righe.
Io li trovo molto comodi. Quelli scritti da me, intendo.
Li ho usati anche per java, quando ho tentato di impararne le fondamenta.
Anche un makefile di poche righe puo' essere utilissimo per chi sviluppa in
ambiente testuale:
pensa a quante volte puoi benissimo digitare "make" (qualsiasi file tu abbia
modificato del tuo progetto)
invece di scrivere ogni volta
gcc -Wall -c nome_file.c
gcc nome_file.o altro_file.o ... ultimo_file.o -o nome_eseguibile
Un'altra faccenda e' spulciarsi i makefile di apache, php o addirittura del
kernel di linux...
... quelli sono tosti!
Poi se ci hai invece un ambiente grafico con un ambiente RAD ecc. ecc.
allora e' vero, che te ne fai dei makefile?
Pero' il senso di avere sotto controllo il codice e l'intero processo di
compilazione, gli ambienti tipo Visual * non me lo danno (nonostante tutti
gli enormi vantaggi che essi offrono).
Ciao,
Ema