2010-05-04 14 views
7

Ho i file due C++, dico file1.cpp e file2.cpp comedichiarazione di funzione in C e C++

//file1.cpp 
#include<cstdio> 
void fun(int i) 
{ 
    printf("%d\n",i); 
} 

//file2.cpp 
void fun(double); 
int main() 
{ 
    fun(5); 
} 

Quando compilo loro e collegamento come C++ file, ottengo un errore "undefined reference to divertimento (doppio)".
Ma quando faccio questo come file C, non ottengo l'errore e 0 viene stampato al posto di 5.
Spiegare la motivazione.
Inoltre, desidero chiedere se è necessario dichiarare una funzione prima di definirla in quanto
Non l'ho dichiarata in file1.cpp ma non è presente alcun errore nella compilazione.

+2

Off topic: se una qualsiasi delle tue precedenti domande ha risposto in modo soddisfacente, devi tornare indietro e accettare le risposte. Solo per essere gentile. – outis

+0

Solo per aggiungere @outis: così facendo aumenterà le possibilità che qualcuno risponda alle tue domande. – ereOn

risposta

6

Questo è molto probabilmente a causa della funzione di sovraccarico. Durante la compilazione con C, la chiamata a fun(double) viene convertita in una chiamata alla funzione di assemblaggio _fun, che verrà collegata in una fase successiva. La definizione attuale ha anche il nome dell'assembly _fun, anche se accetta un int invece di un double e il linker lo userà allegramente quando viene chiamato fun(double).

C++ d'altra parte storpia i nomi di montaggio, così avrai qualcosa di simile [email protected] per fun(int) e [email protected] per fun(double), in modo che il sovraccarico di lavoro. Il linker vedrà che questi hanno nomi diversi e genera un errore che non riesce a trovare la definizione per fun(double).

Per la seconda domanda è sempre consigliabile dichiarare i prototipi di funzione, generalmente eseguiti in un'intestazione, soprattutto se la funzione viene utilizzata in più file. Ci dovrebbe essere un'opzione di avviso per la mancanza di prototipi nel compilatore, gcc usa -Wmissing-prototypes.Il tuo codice sarebbe migliore se impostato come

// file1.hpp 
#ifndef FILE1_HPP 
#define FILE1_HPP 
void fun(int) 
#endif 

// file1.c 
#include "file1.hpp" 
... 

// file2.c 
#include "file1.hpp" 
int main() 
{ 
    fun(5); 
} 

Non avresti più prototipi in conflitto nel programma.

+0

Ma perché stampa 0 anziché 5? –

+0

@Hap Poiché sta interpretando i bit che rappresentano 5.0 come numero intero, che ha un risultato indefinito –

+3

La rappresentazione esadecimale di IEEE-754 double 5.0 sarebbe 0x4014000000000000. Se il tuo sistema è little-endian come x86, la lettura dei primi quattro byte di quello fuori pila sarebbe 0, che verrà quindi stampato. –

-3
#include <stdio.h> 

int Sum(int j, int f) 
{ 
    int k; 
    k = j + f; 
    return k; 
} 
main() 
{ 
    int i=3; 
    int j = 6; 

    int k = sum(i,j); 

    printf("%d",k); 
} 

uscita è 9

+6

Sono completamente perso per ciò che questo ha a che fare con la domanda. – MBennett

+1

Il tuo programma non si compila, per non parlare di rispondere alla domanda. – avakar

+0

La tua risposta ha qualche link alla domanda? – Ashish

5

Questo perché C++ permette di sovraccaricare le funzioni e C non lo fa. E 'valida per avere questo in C++:

double fun(int i); 
double fun(double i); 
... 
double fun(int i) { return 1;} 
double fun(double i) { return 2.1; } 

ma non in C.

La ragione non siete in grado di compilare con il vostro compilatore C++ è perché il compilatore C++ vede la dichiarazione doppio e cerca di trovare una definizione per questo. Con il compilatore C, dovresti avere anche un errore per questo, penso che non hai inserito il codice esattamente come hai detto tu quando esegui il test con il compilatore C.

Il punto principale: C++ ha sovraccarico di funzione, C no.

+0

ho compilato e linkato due file con il compilatore C come gcc -c file1.c gcc -c file2.c gcc -o prog file2.o file1.o Non ha mostrato alcun errore e il risultato è venuto come 0 . –

+0

Il codice C è effettivamente invalido per quanto riguarda lo standard, tuttavia, in pratica, i nomi dei simboli contengono solo il nome della funzione, non l'intera firma, rendendo l'errore invisibile al linker. – avakar

+0

quando lo si compila con gcc, vedere cosa succede se si aggiungono questi interruttori -Wall -Werror –

1

C++ (una bestia sadica, sarete d'accordo) piace manipolare i nomi delle funzioni. Così, nel file di intestazione per la parte C: in alto:

#ifdef __cplusplus 
extern "C" {` 
#endif 

in fondo:

#ifdef __cplusplus 
} 
#endif 

Questa persuaderà che non manipolare alcuni dei nomi. Guarda here

O, nella vostra cpp si potrebbe dire

extern "C" void fun(double); 
1

Un ritardo del linguaggio C è che esso consente di chiamare le funzioni senza richiedere effettivamente la dichiarazione visibile all'interno della traduzione - presuppone solo che gli argomenti di tali funzioni siano tutti int.

Nell'esempio, C++ consente il sovraccarico e non supporta dichiarazioni di funzioni implicite: il compilatore utilizza la funzione visibile fun (double) e il linker non riesce perché la funzione fun (double) non viene mai implementata. fun (int) ha una firma diversa (in C++) ed esiste come un simbolo univoco, mentre un compilatore C (o linker, a seconda della visibilità) produrrebbe un errore quando dichiarate sia fun (int) che fun (double) come Simboli C

Ecco come si sono evolute le lingue nel corso degli anni (o meno). Il tuo compilatore probabilmente ha un avvertimento per questo problema (dichiarazioni di funzioni implicite).

Vedrete risultati diversi quando dichiarate le funzioni come funzioni C (sono dichiarate come funzioni C++ nell'esempio compilato come file sorgente C++).

C++ richiede che la funzione venga dichiarata prima di essere utilizzata, C no (a meno che non comunichi al compilatore di avvisarti del problema).

0

Quando compilato come C++, è possibile avere due funzioni con lo stesso nome (purché abbiano parametri diversi). In C++ nome mutilazione viene usato così il linker può distinguere i due:

fun_int(int x); 
fun_double(double x); 

Quando viene compilato in C c'è solo una funzione con un nome specifico.
Quando si compila file1.c, viene generata una funzione che legge un numero intero dallo stack e lo stampa.

Quando si compila file2.c si vede che il divertimento() richiede un raddoppio. Quindi converte il parametro di input in una doppia pressione sullo stack, quindi inserisce una chiamata a fun() nel codice. Poiché la funzione si trova in una diversa unità di compilazione, l'indirizzo effettivo non viene risolto qui ma solo quando viene richiamato il linker. Quando viene richiamato il linker vede una chiamata a fun deve essere risolta e inserisce l'indirizzo corretto, ma non ha informazioni di tipo per convalidare la chiamata con.

In fase di esecuzione 5 è ora convertito in un doppio e spinto in pila. Quindi viene chiamato fun(). fun() legge un numero intero dallo stack e poi lo stampa. Poiché un doppio ha un layout diverso rispetto a un intero, ciò che verrà stampato sarà definito dall'implementazione e dipenderà dal modo in cui sia il doppio che l'int vengono disposti nella memoria.

Problemi correlati