Link Error LNK2019



  • Ja, ist es.

    Habe eins allerdings verkehrt betrachtet: Wenn die Funktionen in C geschrieben sind und in C++ benutzt werden sollen, muss der Header wie beschrieben aussehen (schaden kann es hier aber nicht). Da die Situation hier umgekehrt ist, also C++-Code in C benutzt werden soll, müssen die Definitionen der Funktionen natürlich genauso markiert werden. Da ist dafür kein #ifdef nötig, da ja immer als C++ übersetzt wird.

    include "../so/dld.h"
    #include "../hd/ge_types.h"
    #include <iostream>
    #include <vector>
    #include <string>
    #include <fstream>
    #include <cstdio>
    #include <cmath>
    
    using namespace std;
    
    const double pi = 3.14159265;    // Pi
    
    //Private Variables
    
    vector< vector<double> > dld_Mat;    // Matrix with Temperature and corresponding material properties
    
    fstream infile;
    string s;
    
    double dld_Mu0 = 4*pi*1.e-7;    // magnetic constant [H/m]
    
    //noch mehr variablen werden initialisiert und definiert
    
    // ---------------- Funktionsdefinitionen ---------------------
    extern "C" {
    // ----------------------------------------------------
    
    int geth(double x, double t, double *h)
    {
        //blabla   
    }
    
    int get_dld_Mat()
    {
        //blabla
    }
    
    int get_Qv_ind(double x, double r, double t, double T, double *Qv_ind)
    {
       //blabla   
    } 
    
    // ende von extern "C"
    }
    


  • Ich könnte grad verzweifeln.

    Also, wenn ich das extern "C" nur in der cpp-verwende, bekomme ich folgende Fehlermeldung:

    c:\dld\pf_2d_mod\so\dld.cpp(114) : error C2732: Bindungsangaben widersprechen vorheriger Angabe für 'geth'
    c:\dld\pf_2d_mod\so\dld.cpp(113): Siehe Deklaration von 'geth'
    c:\dld\pf_2d_mod\so\dld.cpp(153) : error C2732: Bindungsangaben widersprechen vorheriger Angabe für 'get_dld_Mat'
    c:\dld\pf_2d_mod\so\dld.cpp(152): Siehe Deklaration von 'get_dld_Mat'
    c:\dld\pf_2d_mod\so\dld.cpp(239) : error C2732: Bindungsangaben widersprechen vorheriger Angabe für 'get_Qv_ind'
    c:\dld\pf_2d_mod\so\dld.cpp(238): Siehe Deklaration von 'get_Qv_ind'

    Wenn ich es zusätzlich in der Header Datei verwende (ohne #ifdef):

    c:\dld\pf_2d_mod\so\dld.h(5) : error C2059: Syntaxfehler: 'Zeichenfolge'

    Wenn ich es zusätzlich in der Header Datei verwende (mit #ifdef):

    Über 100 Fehlermeldungen. Einige Beispile:

    c:\programme\microsoft visual studio 8\vc\include\new(53) : error C2732: Bindungsangaben widersprechen vorheriger Angabe für 'operator delete'
    c:\programme\microsoft visual studio 8\vc\include\new(53): Siehe Deklaration von 'operator delete'

    c:\programme\microsoft visual studio 8\vc\include\iosfwd(39) : error C2894: Vorlagen können nicht mit 'C'-Bindung deklariert werden

    c:\programme\microsoft visual studio 8\vc\include\iosfwd(601) : error C2733: Zweite C-Bindung für überladene Funktion 'std::_Traits_helper::copy_s' nicht zulässig
    c:\programme\microsoft visual studio 8\vc\include\iosfwd(597): Siehe Deklaration von 'std::_Traits_helper::copy_s'



    1. Mach nur einen Thread zum gleichen Thema im Forum auf
    2. Versuche nicht C und C++ in einem Header zu mixen und dann von c- und c++ dateien darauf zuzugreifen. (Die c-Datei wird Panik schieben)
    3. Versuche nicht extern "C" class xxxx {};
    4. Versuche nicht extern "C" template...
    5. Versuche nicht extern "C" vector<...>


  • Punkt 1: Verstanden werde ich. Bin nur etwas verzweifelt sorry 🙄

    Punkt 3-5: Habe keine solchen Deklarationen.

    Punkt 2: Ich dachte wenn ich die Funktionsdeklaration in eine Headerdatei schreibe, muss ich dies header-datei dann auch im souce-file mit den zugehörigen Funktionsdefinitionen "includieren". Scheint nicht der Fall zu sei. wenn ich das #include "../so/dld.h" aus der dld.cpp Datei entferne, funktioniert es.

    Vielen Dank, wüsste nicht was ich ohne eure Hilfe machen würde.



  • Habe deinen Source Code mal in ein Projekt gepackt, Returnwerte in
    die Funktionen geschrieben und kompiliert.
    In meiner main Funktion habe ich deine Funktionen auch aufgerufen.
    Klappt.

    Muß also an deinen Projektsettings bzw. an deinen Include Pfaden liegen.



  • Um es nochmal zusammenzufassen:

    Wenn Du in einem C-File einen Header einbindest, der zu einer C-Bibliothek gehört, musst Du nichts unternehmen. extern "C" kennt der C-Compiler nicht.

    Wenn Du in einem C++-File einen Header einbindest, der zu einer C-Bibliothek gehört, müssen die Deklarationen mit extern "C" { ... } umschlossen werden. Damit sowohl ein C- als auch ein C++-Compiler denselben Header verstehen können, kannst Du die Einleitung sowie die schließende Klammer jeweils durch #ifdef abgrenzen. Klar sollte sein, dass nur Deklarationen, die C überhaupt versteht, so exportiert werden können. D.h. keine Klassen, keine Templates, keine Operatoren, keine Überladung.

    Wenn Du ein C-File übersetzt, welches Du in einem C++-File benutzen möchtest, musst Du nichts unternehmen, wenn der Header bereits stimmt.

    Wenn Du ein C++-File übersetzt, welches Du in einem C-File benutzen möchtest, müssen alle Definitionen der Funktionen, welche im Header bereits extern "C" markiert sind, nochmal durch dieses umschlossen werden.

    Für Dich treffen die Punkte zwei und vier zu, weitere Fehler können nur der Klammerung zu verdanken sein. (Achte darauf, dass die schließende Klammer von extern "C" vor irgendwelchen C++-Definitionen kommt).



  • so hab ichs jetzt auch gmeacht. nur mache ich jetzt in dld.cpp kein #include "dld.h". dann gehts. sonst krieg ich fehler.



  • ich habe in der CPP Datei ein #include "dld.h" drin

    Linkerfehler sind immer dann, wenn der Kompilier die Deklaration findet, aber die Implementierung nicht.
    Außderdem hast du normale Funktionen, die du in C als auch in C++ Klassen verwenden kannst auch ohne extern "C" und das ganze Geraffel.
    Der C++ Kompiler ist doch viel besser, weil er den Funktionsnamen und die Parameter beachtet. Durch extern "C" verklickerst du dem Kompiler nur, dass
    er den Funktionsnamen beachten soll. Das ist doch an dieser Stelle völliger
    Quatsch.

    Die gleichen Funktionen kannst du auch in eine Klasse stopfen, dann schon ehr nach C++ aus, obwohl dann noch eine Menge fehlt.



  • Diese extern "C" Sache kann ich im headerweglassen weglassen. Im cpp brauche ich das aber. Sobald ich jedoch #include "dld.h" in dld.cpp schreibe, bekomme ich die Linker-Fehler. Wenn ich es weglasse, scheint alles zu funktionieren. Anscheinend findet der Linker die Definition der Funktionen in dld.cpp, auch wenn da dld.h nicht "includiert" ist.

    Naja,Hauptsache es läuft irgendwie.
    Nochmal Dank an alle, dies sich zu diesem Thema geäussert haben.



  • schokomann schrieb:

    Der C++ Kompiler ist doch viel besser, weil er den Funktionsnamen und die Parameter beachtet.

    Eben. Und wenn der C-Compiler diese Funktion dann importieren soll, findet er sie nicht, weil er eben das nicht tut.

    pitaz schrieb:

    Diese extern "C" Sache kann ich weglassen.

    An welcher Stelle?

    Magst Du noch mal das komplette Projekt in seiner jetzigen (funktionierenden) Form posten?

    EDIT2:
    Achja, Du übersetzt schon das, was die Endung .cpp hat, mit einem C++-Compiler, und das, was die Endung .c hat, mit einem C-Compiler, ja?

    EDIT:
    Beispielhaft sollte das so aussehen:

    // funktionen.h
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    void funktion(int param);
    
    #ifdef __cplusplus
    }
    #endif
    
    // funktionen.cpp
    #include "funktionen.h"
    
    extern "C" {
        void funktion(int param)
        {
        }
    }
    
    // programm.c
    #include "funktionen.h"
    
    int main()
    {
        funktion(12);
    }
    


  • Er nimmt VS 2005 und seine Funktion hat nichts C specifisches was der C++ von VS 2005 nicht könnte. Also braucht er dieses extern "C" nicht.

    Nur wenn man diese uralten C Funktionen deren schreibweise auch nicht anders
    ist einbindet und einen C++ Kompiler verwendet, dann muss man das manchmal machen.
    Sonst geht das auch ohne und das hat nichts mit den hier beschriebenen Linker Fehlern und den gezeigten Funktionen zu tun.



  • Also, das "gesamte" (jedenfalls Teile der 3 Files) nochmal:

    dld.h:

    #ifndef DLD_H
    #define DLD_H
    
    //#ifdef  __cplusplus
    //extern "C" {
    //#endif 
    
    int geth(double x, double t,  double *h);
    int get_Qv_ind(double x, double r, double t,  double T, double *Qv_ind);
    int get_dld_Mat();
    
    //#ifdef __cpluspus
    //}
    //#endif
    
    #endif
    

    dld.cpp

    //#include "../so/dld.h"
    #include "../hd/ge_types.h"
    #include <iostream>
    #include <vector>
    #include <string>
    #include <fstream>
    #include <cstdio>
    #include <cmath>
    
    using namespace std;
    
    const double pi = 3.14159265;	// Pi
    
    //Private Variables
    
    vector< vector<double> > dld_Mat;	// Matrix with Temperature and corresponding material properties
    									// Mat[T][i] = ith property at Tm
    									// i=0: Temperature  (=T)  [C]
    									// i=1: thermal conductivity [W/(m*K)]
    									// i=2: heat capacity [J/(kg*K)]
    									// i=3: density [kg/m3]
    									// i=4 resistivity [Ohm/m]
    fstream infile;
    string s;
    
    double dld_Mu0 = 4*pi*1.e-7;	// magnetic constant [H/m]
    
    //Parameters of Heating/Cooling-Device
    
    double dld_hc_x0 = 0.2;			//absolute start coordinate of left end of Heating/Cooling-Device [m]
    double dld_hc_v = 0.005;			//velocity of cooling device [m/s]
    
    //Noch mehr solche Variablen werden initialisiert und definiert.
    
    //Wird in den anderen 3 Funktionen benötigt
    double evalfx(double x_coil, double l_coil, double r_coil, double x)
    {
    	return 1/(2*l_coil) * ((x_coil+l_coil-x)/sqrt(pow(x_coil+l_coil-x,2) + pow(r_coil,2)) - (x_coil-x)/sqrt(pow(x_coil-x,2)+pow(r_coil,2)));
    }
    
    //Wird in den anderen 3 Funktionen benötigt
    double evalh(double a1, double a2, double xc, double b, double x)
    {
    	return (a2-a1)/pi*atan(b*(x-xc))+(a2-a1)/2+a1;
    }
    
    extern "C"{
    
    int geth(double x, double t, double *h)
    {
       //Funktiondefinition	
    }
    
    int get_dld_Mat()
    {
       //Funktionsdefinition
    }
    
    int get_Qv_ind(double x, double r, double t, double T, double *Qv_ind)
    {
       //Funktionsdefinition	
    }
    }
    

    so_temp.c:

    #include <stdio.h>
    #include <math.h>
    
    #include  "../hd/ge_types.h"
    
    #include  "../hd/pa_parallel.h"
    
    #include  "../hd/so_routines.h"
    
    #include  "../hd/me_interface.h"
    #include  "../hd/el_variables.h"
    #include  "../hd/me_variables.h"
    #include  "../hd/ma_variables.h"
    #include  "../hd/nl_variables.h"
    #include  "../hd/co_variables.h"
    #include  "../so/dld.h"
    
    static int so_nTrias, so_nQuads, so_nElems, so_nNQuads, so_nCQuads, so_nNodes;
    
    //Auch hier werden zusätzlich noch einige Variablen deklariert
    
    static int tl_so_ThermoSolve
    (
        VOID
    );
    
    static int tl_so_HeatSurfaceFluid
    
        int   nNodes,       
    
        double pNodalArea[],   
        int   Mat[],         
        double Temp[],
        double time,                                                                                
        double Q[]                       
    
    );
    
    //Deklaration weitere Funktionen (in C)
    
    //Definition der Funktionen
    
    //geth, get_dld_Mat und get_Qv_ind werden nun in den Funktionen tl_so_ThermoSolve und tl_so_HeatSurfaceFluid aufgerufen
    

    Wenn ich das extern "C" in dld.cpp weglasse, kriege ich wieder die Linker-Fehler



  • schokomann schrieb:

    Er nimmt VS 2005 und seine Funktion hat nichts C specifisches was der C++ von VS 2005 nicht könnte. Also braucht er dieses extern "C" nicht.

    Das stimmt nicht, weil eben, wie Du bereits zutreffend festgestellt hast, der C++-Compiler die Funktionssignaturen beachtet, und ein C-Compiler nicht. Ein C++-Compiler erzeugt also Funktionen unter Beachtung der Signatur, aber der C-Compiler, der diese Objekte benutzen soll, sucht die Funktionen ohne die Signatur zu beachten. Extern "C" braucht man auch nicht manchmal wenn der Compiler Lust drauf hat, sondern zu fest definierten Zwecken, von denen der hier (nicht nur manchmal) einer ist.

    Beispiel:
    Ein C++-Compiler übersetzt die Funktion "void function(int param)" und nennt sie, weil er die Signatur beachtet, im Objekt "function_i4". Ein C-Compiler übersetzt ein Programm, welches die Funktion deklariert, und sucht sie, weil er die Signatur nicht beachtet, unter dem Namen "function". Der Linker fügt nun beide Objekte zusammen und stellt fest, dass es "function" nicht gibt.

    @pitaz:

    LordJaxom schrieb:

    Für Dich treffen die Punkte zwei und vier zu, weitere Fehler können nur der Klammerung zu verdanken sein.

    Wie ich bereits vermutet hatte, in der H-Datei fehlt die schließende Klammer von extern "C", weil Du __cpluspus abfragst, statt __cplusplus.



  • Oje, das geht auf meine Kappe, den exakten Typo habe ich leider drüben im MFC-Forum gemacht 😞



  • sollte ich denn auch ein #include "dld.h" in dld.cpp haben? Funktioniert jedenfalls ohne.

    Danke für den Hinweis, jetzt funktionierts auch wenn ich #include "dld.h" drinlasse.


Anmelden zum Antworten