Newsgroup: it.comp.lang.c
Titolo: Funzioni C++

Salve a tutti
Spero di non essere OT (in tal caso chiedo gentilmente di reindirizzarmi in
un NG piu' adatto), ma avrei un quesito da porre ai programmatori C.
C'e' modo di linkare una funzione C++ in un modulo C?
Come si puo' fare?
Non so se sono stato troppo generico, se avete bisogno di ulteriori
informazioni chiedete pure..
Grazie a tutti
Rex

 Come si puo' fare?
puoi dichiarare la funzione C++
extern "C" {
tipo mia_func(arg, arg,...);
};
e renderla compatibile col linker C.
Ad essere sincero, non so se esista nel C99 la keyword
extern "C++" {};
??? (ma credo di no...)

 wrote in message
news:B4Po6.4956$GR5....@news2.tin.it...


Come si puo' fare?
No. Per utilizzare codice C++ e' richiesto che il main
sia scritto in C++... ad un programma C++ pero' si
possono in genere linkare funzioni C senza problemi
(con le opportune dichiarazioni).
Questa asimmetria e' dovuta al fatto che se si usa
codice C++ sono necessarie delle inizializzazioni
specifiche che devono avvenire prima dell'esecuzione
di main e le librerie di runtime C non prevedono questa
possibilita'.
HTH
Andrea
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff

 possibilita'.
scusa andrea, perche' allora questo codice linka e compila?
// ext_c.cpp
extern "C" {
int funz(char *n ){
    int i = strlen(n);
    char *nw  = new char[i];
    for (int len= 0; len < i ; ++len){
        nw[len] = n[len]^0x49;
        n[len] = nw[len];
    }
    delete nw;
    return 0;
}
};
// ext_c.c
#include <stdio.h>
extern int funz(char*);
int main(void){
    char s[] = "prova di funzione c++";
    funz(s);
    printf("%s\n",s);
    return 0;
}
[oscar@localhost varie]$ g++ ext_c.cc -c -Wall
[oscar@localhost varie]$ gcc ext_c.c -c -o ext_c1.o -Wall
[oscar@localhost varie]$ gcc ext_c.o ext_c1.o -o extc -Wall
[oscar@localhost varie]$ ./extc
9;&?(i- i/<'3 &',i*bb
merito del gcc, o di linux, o di che altro?

 e renderla compatibile col linker C.
Perfetto, funziona tutto, grazie.. :-))
Rex


extern "C" {
...
}
Perche' cosi' dichiari un gruppo di funzioni C in un modulo C++, che non e'
la stessa cosa di aver dichiarato una funzione C++ normale.
Serve piu' che altro per l'opposto di quello che chiede RexRatio, cioe' per
usare codice C in progetti C++.
Se compili C++ e generi .OBJ o .LIB, questi non li puoi linkare con sorgenti
compilati in C.
ciao
donCiccio

 sorgenti compilati in C.
invece e' esattamente quello che ho fatto, e va...

invece e' esattamente quello che ho fatto, e va...
Hai usato extern "C".
Con questa direttiva disabiliti il "name mangling" tipico del C++ che
e' un linguaggio "type-safe".  In generale, non puoi linkare codice
C++ a codice C.
--
Andrea Laforgia (ICQ 87230455)
http://www.geocities.com/AndreaLaforgia
"ci sono tre tipi di persone nel mondo : quelli che
 sono bravi in matematica e quelli che non lo sono."

E cosa sarebbe una funzione C++???????????
Ipotesi assurda : una funzione scritta in C++ ?


scusa andrea, perche' allora questo codice linka e compila?
Mi sembra che ci sia ancora una volta confusione sul
concetto di "funziona". Un programma che usa sia codice
C che codice C++ richiede che abbia un main scritto
in C++. Ci sono motivi precisi per questa limitazione
(ad esempio l'inizializzazione delle istanze statiche
e l'istanziazione di template). Molto codice C++
"normale" si basa in modo pesante su queste parti
del linguaggio (ad esempio la gestione I/O)...
Il fatto che tu sia riuscito a scrivere quella funzione,
con quel compilatore, su quel sistema operativo, in quel
momento della giornata e, per quanto puoi osservare tu,
non sia esploso il monitor non significa che la cosa
"funziona". La cosa sembra funzionare solo perche' non
hai guardato bene.


usare codice C in progetti C++.
No, serve esattamente per gli scopi di RexRatio, ovvero utilizzare una
funzione scritta in C++ in un codice C.  Con la direttiva in
questione, il compilatore C++ traduce il codice C++ in codice oggetto
senza decorazione dei nomi, rendendolo compatibile con il collegamento
a codici oggetto scritti in C.


 hai guardato bene.
Scusa ma non sarebbe piu' costruttivo un discorso del genere:
Funziona, se:
- utilizzi una dichiarazione extern "C" { ]
- rinonimi la tua main in main_C( )
- crei un modulo C++ con questa semplicissima funzione:
int main( int argc, char ** argv ){ return main_C( argc, argv ); }
P.S.
Mi sai che te la sei presa troppo per lo "sfotto" ( e comunque devo dire 
che grazie alla tua osservazione ho imparato che e' meglio avere una main 
C++ )

 a codici oggetto scritti in C.
Scusa ma che funzioni scriveresti che poi linki con un progetto .C?
Sicuramente sono funzioni gia' in C per logica, cioe' non credo proprio che
tu riesca a linkare con un progetto .C funzioni che usano classi. Anche solo
la gestione di new e delete, dove li trova il compilatore/linker C?
ciao
donCiccio

la gestione di new e delete, dove li trova il compilatore/linker C?
Quando si parla di funzioni scritte in C++, non si intende
necessariamente funzioni che usano classi.  Il C++ e' un linguaggio
diverso dal C ed e' type-safe per definizione.  Questo significa che
il compilatore C++ genera codice in modo diverso da come farebbe un
compilatore C (decorazione dei nomi, ecc...).  Abolendo queste
caratteristiche, il codice C++ e' compatibile con il codice C.  Tieni
anche presente che new e delete vengono generalmente tradotte dal
compilatore C++ in chiamate a malloc e free.  


Ok!
ma faro' qualche programmino di prova, per convicermi meglio,
ciao
donCiccio

 compilatore C++ in chiamate a malloc e free.
qui ho fatto il prog di prova e non risulta vero, almeno con il
BorlandC++3.1, che chiama una funzione 'operator new (unsigned int)' al cui
interno poi viene chiamata la malloc.
Codesta funzione fa parte della libreria standard (file CL.LIB), che il
compilatore utilizza sia per progetti C sia per progetti C++, per cui il
tutto fortunosamente funziona. Si perche' se usassi una .LIB per progetti C
puri, quella funzione non ci  sarebbe e in fase di link avrei un 'unresolved
external'.
Confermo ancora quanto scritto in precedenza 'extern "C"' serve per poter
utilizzare codice C in progetti C++.
ciao
donCiccio

 ho imparato che e' meglio avere una main C++ )
Non e' meglio. E' obbligatorio nel caso generale...
se in qualche caso ne puoi fare a meno e' semplicemente
una coincidenza.
Fra l'altro personalmente ti consiglierei di ricompilare
*tutto* il codice in C++ visto che le modifiche che
dovresti apportare non dovrebbero essere moltissime
e per la maggior parte abbastanza ovvie (ad esempio
aggiungere qualche cast da void* a puntatore specifico).
Programmi ben scritti in C sono normalmente compilabili
in C++ (a parte qualche intervento marginale necessario
e segnalato dal compilatore C++).
Se posso permettermi la curiosita'... quale e' il motivo
di dover compilare solo una funzione in C++ ?


utilizzare codice C in progetti C++.
extern "C" serve ad abolire la decorazione dei nomi in un codice C++ e
a renderlo compatibile con codice C.  Serve per riallineare i due
linguaggi.  Ti consiglio di leggere un manuale del linguaggio C++.


non ci siamo. Non puoi fare compatibile il C++ con il C solo per name
mangling.
non te la prendere, questa e' solo la mia opinione (e quella di Griffini),
non sono un professore, ma un semplice programmer che puo' anche essersi
sbagliato (ma sono di coccio e prima di ammetterlo lotto fina alla morte
:-))
ciao
donCiccio

mangling.
Ci risiamo.  IO MI STO RIFERENDO AL CASO SPECIFICO DI REXRATIO e di
tutti i casi in cui extern "C" rende il codice C++ compatibile con gli
altri linguaggi che lo interfacciano.   
Ti e' tanto difficile capirlo ?
--
Andrea Laforgia (ICQ 87230455)


Con C++ Builder 5 apro una nuova applicazione console C (attenzione :
non C++).
Aggiungo al progetto un file .CPP contenente la seguente funzione :
// mymodule.cpp
void swap( int *a, int *b )
{
     int t = *a ;
     *a = *b ;
     *b = t ;
}
Il corpo del modulo principale .C e' :
// mainprog.c
#include <stdio.h>
extern void swap( int *a, int *b ) ;
int main()
{
    int a = 3, b = 4 ;
    swap( &a, &b ) ;
    printf( "a = %d, b = %d\n", a, b ) ;
    return 0 ;
}
Compilo.
Risultato :
[Linker Error] Unresolved external '_swap' referenced from
D:\PROGRAMMI\BORLAND\CBUILDER5\PROJECTS\MAINPROG.OBJ
E' un problema chiaramente dovuto alla decorazione dei nomi effettuata
con il codice .cpp.  La elimino, applicando extern "C".
Riscrivo mymodule.cpp nella forma seguente :
// mymodule.cpp
extern "C" {
   void swap( int *a, int *b )
   {
        int t = *a ;
        *a = *b ;
        *b = t ;
   }
}
Compilo.
Output del programma :
a = 4, b = 3
--
Andrea Laforgia (ICQ 87230455)


malloc e free (almeno e' cosi' nel 99% dei casi).
Non sta scritto da nessuna parte che chiamare "operator new" viene
risolto con una chiamata a "malloc". Lo standard garantisce solo
l'opposto ovvero che chiamare "malloc" sicuramente *NON* chiama
operator new (questo ho l'impressione che sia stato garantito per
permettere ad un utente di implementare la propria versione di
operator new e operator delete appoggiandosi a malloc/free).
Il fatto che operator new e operator delete vengano risolti inline
in chiamate a "malloc" compatibili con la libreria C e' una illazione.
Se anche trovi un compilatore di una specifica versione che in un
caso fa quello che dici non significa assolutamente nulla...
Ad esempio in BCC55 quando si chiama operator new il compilatore
genera delle chiamate a
    @$bnwa$qui
mentre le allocazioni fatte da C chiamano
    _malloc
cosa non molto sorprendente visto che nel caso del C++ il compilatore
deve gestire le exceptions standard (e di conseguenza e' fra l'altro
inevitabile che si tirino in ballo le classi).
Questo significa anche che operator new chiama una funzione della
libreria C++ a tutti gli effetti (e non un semplice "wrapper").
Tutto questo non toglie che gli autori del compilatore BCC55
abbiano cercato di mantenere anche questa compatibilita' con
dei "trucchi" interni.
Addirittura se scrivi un modulo .cpp contenente
  #include <iostream>
  namespace {
    struct X
    {
      X() {
        std::cout << "Hello, CPP world.\n" << std::endl;
      }
    };
    X x;
  };
 
e fai il link con un modulo .c contenente main() all'esecuzione
ottieni comunque (prima dell'esecuzione di main) il "saluto"
da parte del modulo .cpp.
Questo significa che compilatore/linker hanno fatto ben piu'
di quanto richiesto dalla compilazione di progetti "C": in
"C" non c'e' modo di ottenere l'esecuzione di codice utente
prima della partenza di main (purtroppo... ci sono infatti casi
in cui farebbe comodo).
Che queste cose funzionino non e' pero' richiesto dallo
standard ... si tratta di una coincidenza. Secondo me la
risposta corretta alla domanda dell'OP
   "e' possibile chiamare funzioni C++ da progetti C"
e' semplicemente "No".


 di dover compilare solo una funzione in C++ ?
La butto la' ( non ho mai avuto questa esigenza ): un programma scritto in 
C gia' esistente a cui bisogna aggiungere/modificare qualcosa; il punto che 
mi ha sempre interessato e' capire che liberta'ho di scegliere un'altro 
linguaggio oltre al C: il C++ "dovrebbe" andare bene con alcune indicazioni.
Tra l'altro ho notato che nel mio g++ ( debian potato 2.2, gcc 2.95.2 ) gli 
inizializzatori del programma e i terminatori sono uguali ( o meglio il 
pacchetto g++ non ne ha nessuno e si basa su quelli del gcc ... )...

 }
questa e' una funzione C per logica, anche se la compili in C++, cioe' del
C++ non usa assolutamente nulla!
puoi benissimo aggiungerla al tuo progetto C e compilare tutto in C. Non
c'e' nessun motivo di compilare questa funzione in C++. Se i problemi di
RexRatio erano questi bhe, allora hai ragione tu, ma se RexRatio ha una
funzione che e' scritta in C++ cioe' non la puoi compilare se non usi un
compiler C++, allora....
il mio esempio di prova e' stato il seguente:
------------- file pro1.cpp
class myclass
{
  int * vet;
public:
  myclass( int l ) { vet = new int[l] ; }
  ~myclass( void ) { delete( vet ); }
};
myclass pippo(10); // oggetti statici
myclass pluto(10);
extern "C"
{
  int fun1 ( int p )
  {
    myclass mc(p);
    return p;
  }
}
------------- file pro2.c
extern int fun1 ( int p );
int  main ( void )
{
  return fun1( 1 );
}
-----------------
con questo codice, secondo lo standard C, non sarei dovuto riuscire a
linkare i 2 file, anche se fun1 e' dichiarata in un blocco extern "C",
perche' vengono usate new e delete che in C non esistono (perche' vengono
compilate come chiamate a funzioni diverse da malloc e free), e vengono
allocati 2 oggetti statici i cui costruttori non dovrebbero venir richiamati
da un main C.
Ma invece tutto funziona, solo perche' il BC usa lo stesso codice di startup
e le stesse librerie sia per progetti C sia per progetti C++, ma questo non
vuol dire che sia una regola di tutti i compilatori, ne che sia contemplato
dallo standard, e probabilemte e' lo stesso motivo per cui anche a Oscar
Luini il suo codice funziona.
Sono contento che Griffini ti abbia risposto al tuo mex precedente.
Ovviamente io condivido il suo punto di vista. :-)
ciao, ma sono ancora convinto di quello che ho detto
donCiccio

 }
questa e' una funzione C per logica, anche se la compili in C++, cioe' del


 }
questa e' una funzione C per logica, anche se la compili in C++, cioe' del


 }
questa e' una funzione C per logica, anche se la compili in C++, cioe' del


 }
questa e' una funzione C per logica, anche se la compili in C++, cioe' del


e' semplicemente "No".
Secondo me e' "dipende".
Quando queste funzioni sono anche valide funzioni C, si possono
linkare.  Vedi il mio esempio di compilazione ben riuscita.


Sono contento che Griffini ti abbia risposto al tuo mex precedente.
Ed io sono contento di aver risposto.


 }
questa e' una funzione C per logica, anche se la compili in C++, cioe' del
C++ non usa assolutamente nulla!





perche' vengono usate new e delete che in C non esistono (perche' vengono
compilate come chiamate a funzioni diverse da malloc e free), e vengono
allocati 2 oggetti statici i cui costruttori non dovrebbero venir richiamati
da un main C.
Ma invece tutto funziona, solo perche' il BC usa lo stesso codice di startup
e le stesse librerie sia per progetti C sia per progetti C++, ma questo non
vuol dire che sia una regola di tutti i compilatori, ne che sia contemplato
dallo standard, e probabilemte e' lo stesso motivo per cui anche a Oscar
Luini il suo codice funziona.
Sono contento che Griffini ti abbia risposto al tuo mex precedente.



non l'avevo capito.
Allora il risultato e' mica questo:
funzioni C++ che non usano per niente il C++ ma che sono ricompilabili
tranquillamente in C, le posso aggiungere ad un progetto C mettendo la loro
dichiarazione in un blocco extern"C", per tutte le alte non si puo' fare! e
giusto?
ciao
donCiccio

giusto?
No.
Non e' detto che funzioni scritte in C++ siano ricompilabili
tranquillamente in C, anche se si limitano ad osservare la sintassi
del C.  Funzioni C++ SCRITTE CON LA SEMANTICA DEL C++ e che sfruttano
il solo subset C (che e' un'evoluzione del C standard) sono linkabili
ad un progetto C.
Direi, comunque, che ne abbiamo parlato abbastanza...


linkare.  Vedi il mio esempio di compilazione ben riuscita.
Hehehe... "Si... basta che la funzione non sia una
funzione C++ ma sia una funzione C".
Non ti rendi conto di quanto suona assurda questa risposta ?
Lasciando perdere le tue (secondo me insensate) prove in cui
hai usato lo stesso compilatore (C++) per compilare sia le
parti C che quelle C++.


Direi, comunque, che ne abbiamo parlato abbastanza...
Esatto. Anche troppo.




gcc e g++ sono piu' che fortemente integrati. In realta' il
compilatore e' unico: in "man g++" si legge
   ...   
   DESCRIPTION
     The C and C++ compilers are integrated; g++ is a script to
     call gcc with options to  recognize  C++.   gcc  processes
     input  files  through  one or more of four stages: prepro­
     cessing, compilation, assembly,  and  linking.   This  man
     page  contains  full  descriptions  for  only C++ specific
   ...



OK, alla prossima
ciao
donCiccio

Scusate se ritorno sull'argomento, ma mi sento obbligato a fornire alcune
specifiche.
Premesso che -extern "C"- ha risolto tutti i miei problemi (mi scuso per
l'ignoranza, ma io
extern "C" l'ho sempre usata all'inverso cioè per linkare del C ad un main
C++), il motivo
per cui non è stato ricompilato tutta la parte C in C++ è sostanzialmente la
mole della parte
C, estremamente superiore alla parte C++ (un solo sorgente, quello
incriminato, di un migliaio
di righe di codice).
Questo famigerato sorgente purtroppo è stato compilato in C++ perché ho
dovuto fare parecchie
chiamate alla libreria di classi DAO (un pezzo delle MFC per parlare coi
database).
Essendo quest'ultime piuttosto antipatiche, in questo sorgente vengono anche
gestite tutte le
eccezioni del caso.
Come ultima cosa il compilatore usato è VC++ 6.0 sia per il codice C che per
il codice C++.
Spero di avervi detto qualcosa di utile,
ciao
Rex.

 C++),
Non vorrei scatenare nuovamente il thread, ma hai sempre fatto la cosa
giusta. :-)
ciao
donCiccio

 extern "C", e il progetto sicuramente funziona!
 
Credo che neanche questo sia corretto. L'uso di costrutti extern 
"C++"/extern "C", specificano come associare simboli alle funzioni ( 
insomma la presenza/ o l'assenza di decorazioni ). Tutto il resto e' solo 
una conseguenza NON GARANTITA. Ovvero se richiamo funzioni esterne scritte 
in C che fanno affidamente a qualche inizializzazione, non e' detto che 
funzionino anche in C++ ( infatti l'header dei programmi non e' detto che 
siano uguali .... )
Codice C++ ( ovvero una main in C++ ) forse offre migliori garazie. Non 
credo che nessuno possa giurarci in generale. Ci stanno casi particolari, 
ma questa e' un'altra questione...

 compilatore e' unico: in "man g++" si legge
Non proprio: la compilazione avviene in due passate, e la prima passata e' 
fatta da programmi diversi a seconda se si tratta di C ( 
/usr/lib/gcc-lib/i386-linux/2.95.2/cc1 ), C++ ( 
/usr/lib/gcc-lib/i386-linux/2.95.2/cc1plus ), fortran 77 ( 
/usr/lib/gcc-lib/i386-linux/2.95.2/f771 ) ed altro
La seconda passata ( /usr/lib/gcc-lib/i386-linux/2.95.2/collect2 ) anchessa 
e' in comune...

Mi sembra si stia discutendo del sesso degli angeli...
Indipendentemente dal linguaggio ( C++,C,fortran ... ) due moduli ( 
supposta la compatibilita dei formati dei moduli ovviamente ) si possono 
sempre linkare; ma affinche' la cosa funzioni e' necessario:
- I nomi delle funzioni richiamate da un modulo devono corrispondere a 
quelle dell'altro ( e' qua' entrano in gioco i costrutti del C++ extern 
"C"/"C++", ma non dimentichiamo che ogni compilatore e' libero di inserire 
le proprie stranezze )
- ci siano tutte le librerie ( c, c++, matematiche etc etc )
- il codice di startup inizializzi l'ambiente in maniera corretta
Mi sembra che queste considerazioni ( che definire banali ) non siano 
collegate minimante al fatto che si linki codice C++, a codice C o 
viceversa. Per cui il problema e' plataform dipendent; per una ristretta 
cerchia di funzioni la cosa puo' funzionare. Ma non e' detto che funzioni 
per tutte le cobinazioni di funzioni invocate ( sia dei moduli sia della 
libreria ).

 Credo che neanche questo sia corretto.
Perche'?
Non e' una sfida, non ti alterare come Laforgia, ma fammi un esempio in cui
codice C non funzionerbbe correttamente in un progetto C++ (main in C++).
ciao
donCiccio

ma questa e' un'altra questione...
In effetti condivido. A essere pignoli forse non e' nemmeno
detto che questa cosa si possa fare sempre.
Ad esempio a oggi e' improponibile linkare codice C++
a codice C++ che non sia stato generato dallo *stesso*
identico compilatore. Gia' questo la dice lunga.



ho compilato il tuo esempio con BC5.0 e... miracolo funziona! "eccezione =
eccezione".
ma forse BC non fa testo, come si e' gia' detto, fa cose che non dovrebbe
fare pure quando il main e' C e lo linki moduli C++.
ciao
donCiccio