2010-05-04 28 views
7

Ich habe zwei C++ Dateien, sage file1.cpp und file2.cpp alsFunktionsdeklaration in C und C++

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

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

Als ich sie zusammenstellen und als c verknüpfen ++ Dateien, bekomme ich eine Fehlermeldung „undefined Verweis auf Spaß (Doppel) ".
Aber wenn ich dies als C-Dateien, bekomme ich keinen Fehler und 0 wird anstelle von 5 gedruckt.
Bitte erläutern Sie den Grund.
Außerdem möchte ich fragen, ob wir eine Funktion deklarieren müssen, bevor Sie es definieren, weil
Ich habe es nicht in file1.cpp deklariert, aber kein Fehler kommt in Kompilierung.

+2

Off-Thema: Wenn eine Ihrer vorherigen Fragen zu Ihrer Zufriedenheit beantwortet wurde, sollten Sie zurückgehen und die Antworten akzeptieren. Nur um nett zu sein. – outis

+0

Nur zu @outis hinzufügen: Dies erhöht die Chancen, dass jemand Ihre Fragen beantwortet. – ereOn

Antwort

6

Dies ist höchstwahrscheinlich wegen der Funktion Überlastung sagen konnte. Beim Kompilieren mit C wird der Aufruf an fun(double) in einen Aufruf der Assembly-Funktion _fun übersetzt, die zu einem späteren Zeitpunkt verknüpft wird. Die tatsächliche Definition hat auch den Assembly-Namen _fun, obwohl es ein Int statt ein Double dauert, und der Linker wird fröhlich verwenden, wenn fun(double) aufgerufen wird.

C++ auf der anderen Seite mangles die Montage Namen, so dass Sie so etwas wie [email protected] für fun(int) und [email protected] für fun(double), um eine Überlastung bekommen zu arbeiten. Der Linker wird sehen, dass diese unterschiedliche Namen haben und einen Fehler erzeugen, der die Definition für fun(double) nicht finden kann.

Für Ihre zweite Frage ist es immer eine gute Idee, Funktionsprototypen, in der Regel in einer Kopfzeile, zu deklarieren, besonders wenn die Funktion in mehreren Dateien verwendet wird. Es sollte eine Warnoption für fehlende Prototypen in Ihrem Compiler geben, gcc verwendet -Wmissing-prototypes.Ihr Code wäre besser, wenn die Einrichtung wie

// 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); 
} 

Sie würden dann nicht mehrere widersprüchliche Prototypen in Ihrem Programm haben.

+0

Aber warum druckt es 0 statt 5? –

+0

@Hap Weil es die Bits interpretiert, die 5.0 als Integer darstellen, was ein undefiniertes Ergebnis hat –

+3

Die Hexadezimaldarstellung von IEEE-754 double 5.0 wäre 0x4014000000000000. Wenn Ihr System ein Little-Endian-ähnliches System wie x86 ist, würde das Lesen der ersten vier Bytes davon außerhalb des Stapels 0 sein, was dann gedruckt wird. –

-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); 
} 

Ausgabe 9

+6

Ich bin völlig verloren, was das mit der Frage zu tun hat. – MBennett

+1

Ihr Programm kompiliert nicht, geschweige denn die Frage zu beantworten. – avakar

+0

Haben Sie einen Link zu der gestellten Frage? – Ashish

5

Dies liegt daran, C++ Sie Funktionen zu überlasten können und C nicht. Es gilt dies in C haben ++:

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

nicht aber in C.

Der Grund, warum Sie nicht in der Lage sind zu kompilieren Sie es mit Ihren C++ Compiler ist, weil der C++ Compiler die Deklaration als doppelt sieht und versucht eine Definition dafür zu finden. Mit dem C-Compiler sollten Sie auch einen Fehler bekommen, ich würde denken, dass Sie den Code nicht genau so eingegeben haben, wie Sie es beim Testen mit dem C-Compiler getan haben.

Der Hauptpunkt: C++ hat Funktionsüberladung, C nicht.

+0

ich kompiliert und verknüpft zwei Dateien mit C-Compiler als gcc -c file1.c gcc -c file2.c gcc -o prog file2.o file1.o Es sind keine Störungen zeigten und Ergebnis kam als 0 . –

+0

Der C-Code ist tatsächlich in Bezug auf den Standard ungültig, jedoch enthalten die Symbolnamen in der Praxis nur den Namen der Funktion, nicht die gesamte Signatur, wodurch der Fehler für den Linker unsichtbar wird. – avakar

+0

Wenn Sie es mit gcc kompilieren, sehen Sie, was passiert, wenn Sie diese Schalter hinzufügen -Wall -Werror –

1

C++ (ein sadistisches Biest, Sie werden zustimmen) mag die Namen der Funktionen zu vermischen. So wird in Ihrer Header-Datei für den C-Teil: an der Spitze:

#ifdef __cplusplus 
extern "C" {` 
#endif 

am Boden:

#ifdef __cplusplus 
} 
#endif 

Dieser wird reden nicht einige der Namen zerfleischen. Schauen here

OR, in Ihrer CPP Sie

extern "C" void fun(double); 
1

Ein Überbleibsel der C-Sprache ist, dass ermöglicht Funktionen aufgerufen werden, ohne tatsächlich die Deklaration sichtbar in der Übersetzung - es nimmt nur an, dass die Argumente solcher Funktionen alle int sind.

In Ihrem Beispiel erlaubt C++ das Überladen und unterstützt keine impliziten Funktionsdeklarationen - der Compiler verwendet die sichtbare Funktion fun (double), und der Linker schlägt fehl, weil die Funktion fun (double) nie implementiert ist. fun (int) hat eine andere Signatur (in C++) und existiert als eindeutiges Symbol, während ein C-Compiler (oder Linker, abhängig von der Sichtbarkeit) einen Fehler erzeugt, wenn Sie sowohl fun (int) als auch fun (double) als deklarieren C Symbole.

So haben sich die Sprachen im Laufe der Jahre entwickelt (oder auch nicht). Ihr Compiler hat wahrscheinlich eine Warnung für dieses Problem (implizite Funktionsdeklarationen).

Sie sehen andere Ergebnisse, wenn Sie die Funktionen als C-Funktionen deklarieren (sie werden in Ihrem Beispiel als C++ - Funktionen deklariert, wenn sie als C++ - Quelldateien kompiliert werden).

C++ erfordert, dass die Funktion deklariert wird, bevor sie verwendet wird, C nicht (es sei denn, Sie weisen Ihren Compiler an, Sie über das Problem zu warnen).

0

Wenn Sie als C++ kompiliert werden, dürfen Sie zwei Funktionen mit demselben Namen haben (solange sie unterschiedliche Parameter haben). In C++ Namensverkürzung verwendet wird, so dass der Linker die beiden unterscheiden kann:

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

Wenn in C kompiliert nur eine Funktion mit einem bestimmten Namen ist.
Wenn Sie file1.c kompilieren, generieren Sie eine Funktion, die eine Ganzzahl aus dem Stapel liest und sie ausgibt.

Wenn Sie file2.c kompilieren, sieht es, dass das fun() ein Double nimmt. Also konvertiert es den Eingabeparameter in einen doppelten Push-Vorgang auf den Stapel und fügt dann einen Aufruf von fun() in den Code ein. Da sich die Funktion in einer anderen Kompilierungseinheit befindet, wird die tatsächliche Adresse hier nicht aufgelöst, sondern nur, wenn der Linker aufgerufen wird. Wenn der Linker aufgerufen wird, sieht er, dass ein Aufruf von "Spaß" aufgelöst werden muss, und fügt die richtige Adresse ein, aber er enthält keine Typinformationen zum Überprüfen des Aufrufs mit.

Zur Laufzeit wird 5 nun in ein Double konvertiert und auf den Stack geschoben. Dann wird fun() aufgerufen. fun() liest eine ganze Zahl aus dem Stapel und druckt sie dann aus. Da ein double ein anderes Layout als eine Ganzzahl hat, wird das, was gedruckt wird, implementiert und hängt davon ab, wie double und int im Speicher abgelegt sind.

Verwandte Themen