Newsgroup: it.comp.lang.c++
Titolo: Domanda stupida su inclusioni e funzioni

Perché compilando il seguente codice ottengo un errore così:
 
g++ main.cpp -o out
 
/tmp/ccS4W2Rw.o: In function `main':
main.cpp:(.text+0x21): undefined reference to `somma(int, int)'
collect2: ld returned 1 exit status
 
 
 
 
#### main.cpp ####
 
#include <iostream>
#include "functions.h"
 
int main()
{
	int primo = 3;
	int secondo = 5;
 
	int totale = somma(primo, secondo);
	std::cout << totale << std::endl;
 
}
#### FINE main.cpp #####
 
 
 
###### functions.h #####
 
int somma(int a, int b);
 
###### FINE functions.h #####
 
 
 
###### functions.cpp #####
 
#include "functions.h"
 
int somma(int a, int b)
{
	return a+b;
}
 
###### FINE functions.cpp #####
 
Testone

 Perch compilando il seguente codice ottengo un errore cos :

g++ functions.cpp main.cpp -o out
Ciao!

 g++ functions.cpp main.cpp -o out
 
Mi dice che somma è già definita:
 
/tmp/cc7KjwT1.o: In function `somma(int, int)':
main.cpp:(.text+0x0): multiple definition of `somma(int, int)'
/tmp/ccMZr492.o:functions.cpp:(.text+0x0): first defined here
collect2: ld returned 1 exit status
 
Testone

 Mi dice che somma è già definita:
 
mi sembra strano, la dichiarazione multipla del prototipo 
non dovrebbe dare problemi (diversamente dalla ridefinizione 
del corpo).
Ma se lo da, potresti mettere delle clausole include-once in 
ogni .H
 
tipo
 
#infdef Pincopallino_H
#define Pincopallino_H
 
dichiarazioni
 
#endif
 
così anche un ambiente stupido vedrà la prototipizzazione 
solo una volta. E' anche molto efficiente quando crei una 
complicata gerarchia di inclusioni, e poi non ricordando 
bene dove sono le cose, includi tutto sistematicamente.
Con la inclusione condizionale, la prima volta esamina 
tutto, ma in seguito, alle reinclusioni, skippa via tutto 
alla veloce.
 
ciao
Soviet



 
Ti consiglio di usare la keyword "extern" che informa il compilatore
che la definizione di "somma()" si trova in un altro sorgente. E di
evitare l'inclusione multipla definendo delle macro in testa all'header:
 
/* functions.h */
 
#ifndef FUNCTIONS_H
#define FUNCTIONS_H
 
extern int somma(int a, int b);
 
#endif
 
 
-- 
Vincenzo Mercuri | 
www.backbox.org
 

 Testone
 
Nah, vedi che stai compilando qualcosa che non hai scritto :-)
Ciao!
 
P.S.
Per completezza, metti una "barriera d'inclusione" attorno al .h
(#ifndef / #define / #endif)


 
??
Tutti i tuoi .h hanno le extern? :-)
Ciao!

 Tutti i tuoi .h hanno le extern? :-)
...
 
Certo che si ;) Prova a compilare questo programmino:
(sempre con "g++ functions.cpp main.cpp ...")
 
         // main.cpp
         #include <iostream>
         #include "functions.h"
 
         int main()
         {
             std::cout << somma << std::endl;
         }
 
         // functions.h
         int somma;
 
         // functions.cpp
         #include "functions.h"
 
Nel linking compare un messaggio di errore molto simile a quello
che ha riscontrato l'OP. Ho usato solo variabili.
Il problema si puo' risolvere con:
 
         // functions.h
         extern int somma;
 
         // functions.cpp
         #include "functions.h"
         int somma = 0;
 
PS: secondo me è strano comunque l'errore trovato dall'OP. Non c'è stata
una doppia definizione nel suo caso. Forse quello che ha compilato non
è tutto quel che ha postato. Oppure aveva proprio _definito_ la funzione
"somma()" nello stesso header.
 
-- 
Vincenzo Mercuri | 
www.backbox.org
 

 Ciao!
 
In effetti oggi "a freddo" con:
 
g++ functions.cpp main.cpp -o out
 
compila senza errori!
...forse ieri durante le varie prove avrò fatto qualche errorino.
 
Grazie a tutti,
Testone


 
Ovviamente, informi chi include "functions.h" che esiste una variabile
"somma" definita in un qualche oggetto.
 
Ciao!

 "somma" definita in un qualche oggetto.
 
Si. Ho fatto questo esempio perchè mi è stato chiesto se uso "extern"
in tutti i miei header. Lo uso proprio per prevenire questo. Quando
scrivo un header non penso a come dovrò includerlo poi senza commettere
errori. E questo vale un po' per tutto, non delego mai ad altri sorgenti
dei controlli che posso fare ora. Non mi piace essere cosciente di
scrivere potenziali bug.
 
-- 
Vincenzo Mercuri | 
www.backbox.org
 


wrote:

Scusami ma ciò che dici non ha molto senso: stai mischiando i concetti
di dichiarazioni e definizioni, utilizzandoli IMHO male; e siccome so
che conosci benissimo la situazione non ne vedo il motivo!
 
Puoi dichiarare quello che ti pare quante volte ti pare dove ti pare
(a patto che le dichiarazioni siano concordi):
con le funzioni:
int a(void);
int a(void);
int a(void) { return 2; }
 
con le variabili:
extern int a;
extern int a;
int a;
 
sono codici validi.
"Per il popolo" si potrebbe dire che la dichiarazione serve a
promettere al compilatore che un identificatore ancora non definito lo
sarà in seguito (ricordo che i compilatori, da specifiche, fanno un
solo passaggio del codice).
 
Arriviamo alla compilazione: se uso una funzione il compilatore ha
solo bisogno di conoscerne il prototipo, e se uso una variabile il
tipo. In fase di linking, il linker cercherà di risolvere la
"locazione" degli identificatori.
 
Detto questo, tradizionalmente in C/C++ si dice: "beh, visto che non
posso stare a controllare l'ordine di definizione di variabili e
funzioni, facciamo una cosa: mettiamo tutte le definizioni nei .c e
tutte le dichiarazioni nei .h; quando ho bisogno di utilizzare una
funzione includo il .h e poi ci penserà il linker.". Non metto in
dubbio che esistano tante altre soluzioni alternative, curiose e
funzionanti, ma questa metodologia che io sappia è sempre la più
facile e sensata...
 
Ciao!

 funzione includo il .h e poi ci penserà il linker."
 
non capisco cosa c'entri con il mio esempio.
Tu hai ragione sul fatto di includere le dichiarazioni nell'header.
Ma io ho per caso detto il contrario? Uso extern per il linkage esterno
e ho risposto alla domanda se uso extern nei miei header.
 
E se uso extern anche quando si potrebbe evitare mi dici che problema
c'è? Dove non è un fatto di utilità ne faccio una questione di coerenza.
E se hai qualche problema a capirmi vai a spulciare i sorgenti di GCC.
Ti prego di farlo.
 
 
-- 
Vincenzo Mercuri | 
www.backbox.org
 


 
Lo ipse dixit sai anche te che non tiene: vedi allora i sorgenti del
kernel di linux :-)
 
Ciao!

 kernel di linux :-)
 
Hai ragione, ma infatti non suggerisco di farlo perchč lo fanno altri,
il riferimento a quei sorgenti č perchč lě č usato in maniera ricorrente
quello che volevo spiegare. Non postando del codice quello č il primo
esempio utile che mi č venuto in mente per esprimere cosa intendevo.
A presto!
 
-- 
Vincenzo Mercuri | 
www.backbox.org
 


 
Ma no, dai! Vincenzo lo leggo sempre con attenzione e lo stimo molto
per la sua conoscenza di molto superiore alla mia - e sono sicuro che
se anche lui legge i miei post sa che a volte scrivo come se dovessi
criticare anche se non ne ho la minima intenzione :-)
 
Ciao!

 criticare anche se non ne ho la minima intenzione :-)
 
Non dire cavolate, tu sei molto più pragmatico di me, mi piace molto
il tuo modo di risolvere i problemi e fornire soluzioni utili.
Io sono un po' più legato alle teorie e le soluzioni generali,
ma questo è un vizio che mi porto da quando frequento comp.lang.c.
Non prendo i tuoi post come delle critiche personali, ma come
normali affermazioni, certo da confutare se è il caso di farlo.
Ti leggo anch'io con molta attenzione.
Scappo, a Milano è festa e si esce. Ciao! :)
 
-- 
Vincenzo Mercuri | 
www.backbox.org
 


 
Grazie, grazie ;)
CLC lo leggo ma non intervengo, su due post buoni dieci sono d'insulti
vari :D giusto qui su ICLC e ICLC++ c'è un'educazione fuori dalla
norma :-O
Buona festa allora! Qui invece a quanto pare hanno capito che siamo
dei programmatori senza Dio e che possiamo quindi lavorare anche l'8
Dicembre :D
Ciao!

 Mi dice che somma è già definita:
 
mi sembra strano, la dichiarazione multipla del prototipo
non dovrebbe dare problemi (diversamente dalla ridefinizione
del corpo).
Ma se lo da, potresti mettere delle clausole include-once in
ogni .H
 
tipo
 
#infdef Pincopallino_H
#define Pincopallino_H
 
dichiarazioni
 
#endif
 
così anche un ambiente stupido vedrà la prototipizzazione
solo una volta. E' anche molto efficiente quando crei una
complicata gerarchia di inclusioni, e poi non ricordando
bene dove sono le cose, includi tutto sistematicamente.
Con la inclusione condizionale, la prima volta esamina
tutto, ma in seguito, alle reinclusioni, skippa via tutto
alla veloce.
 
ciao
Soviet
 
ma oltre a essere stracompetente in chimica ti intendi pure di 
programmazione??