Frage zu extern "C"



  • pumuckl schrieb:

    Und kann man das so schreiben bzw. sollte man es so machen?

    Nein. Sollte man nicht. #define cplusplus bzw. #define __cplusplus werden vom Compiler gemacht, das solltest du selber garnicht machen.

    wtf?
    Was heißt denn hier "machen"?
    Das vordefinierte Macro heißt __cplusplus. Ohne Doppel-Unterstrich taucht das nicht im C++ Standard auf.



  • Ich hab das ganze jetzt mal von C nach C++ ausprobiert. Meine Funktionen werden ohne Probleme ausgeführt.

    Aber ich bekomme immer diese Warnungen:

    [C++ Warnung] Unit1.c(7): W8065 Aufruf der Funktion 'function' ohne Prototyp
    [C++ Warnung] Unit1.c(9): W8065 Aufruf der Funktion 'function_2' ohne Prototyp
    [C++ Warnung] Unit1.c(11): W8065 Aufruf der Funktion 'system' ohne Prototyp
    

    Wenn ich in my_functions.cpp nicht schreibe:

    void function();
    void function_2();

    Wieso muss ich in my_functions.cpp auch nochmal die Prototypen definieren?
    Das habe ich doch eigentlich schon in my_header.h gemacht.

    main.c

    #include <stdio.h>
    #include "my_header.h"
    
    int main(int argc, char* argv[])
    {
    
    function();
    printf("\n");
    function_2();
    
    system("PAUSE");
    }
    

    my_header.h

    #ifndef my_header
    #define my_header
    
    #ifdef __cplusplus
    
    extern "C" // Ermöglicht die Verwendung von C++ Funktionen in
               // C Programmen
    {
            void function(); 
            void function_2();
    }
    #endif
    #endif
    

    my_functions.cpp

    #include "my_header.h"
    #include <iostream>
    using namespace std;
    
    void function();
    void function_2();
    
    void function()
    {
     cout<<"ok";
    }
    
    void function_2()
    {
     cout<<"funktion 2";
    }
    


  • -.- Wenn ich mein Projekt abspeichere kommt wieder diese Prototyp Warnung, da hab ich mich wohl zu früh gefreut ... 😡

    Obwohl ich in my_function.cpp die Funktionen definiert habe.



  • #ifndef my_header
    #define my_header
    
    #ifdef __cplusplus
    
    extern "C" // Ermöglicht die Verwendung von C++ Funktionen in
               // C Programmen
    {
            void function();
            void function_2();
    }
    #endif
    #endif
    

    Denk mal darüber nach, was hier beim Compiler ankommt, wenn __cplusplus nicht definiert ist. Richtig: garnichts.

    Und dann vergleiche nochmal mit den vorangegangenen Beiträgen, insbesondere verfolge die Diskussion "Warum nimmt man #endif mit in die geschweifte Klammer?" 😉



  • externC schrieb:

    my_header.h

    #ifndef my_header
    #define my_header
    
    #ifdef __cplusplus
    
    extern "C" // Ermöglicht die Verwendung von C++ Funktionen in
               // C Programmen
    {
            void function(); 
            void function_2();
    }
    #endif
    #endif
    

    Das ist ja auch falsch so. Der C Compiler sieht davon GAR nix, weil der Präprocessor alles rausschmeißt; denn __cplusplus ist ja beim C Compiler nicht definiert. Dementsprechend fehlen Dir die Funktionsdeklarationen ("Prototypen" in C-Sprech) und der C-Compiler warnt Dich, dass Du Funktionen später aufrufst, die er noch gar nicht kennt.

    Richtig:

    ...
    
    #ifdef __cplusplus
    extern "C" {
    [b]#endif[/b]
    
    ...
    
    [b]#ifdef __cplusplus[/b]
    }
    #endif
    
    ...
    


  • Wieder die Prototyp Fehlermeldung. 😞

    Ich versteh nicht was da jetzt schon wieder falsch sein soll. (Naja falsch vielleicht nicht denn es Kompiliert ja und läuft. (Ein Lehrer sagte mal "Das sind nur Warnungen das ist nicht so schlimm", aber ob das nicht so schlimm ist da zweifel ich irgendwie dran, den die Warnung wird ja nicht zum Spass ausgegeben.)

    main.c

    #include <stdio.h>
    #include "my_header.h"
    
    int main()
    {
    
    function();
    function_2();
    
    system("PAUSE");
    
    return 0;
    
    }
    

    my_header.h

    #ifndef my_header
    #define my_header
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    void function();
    void function_2();
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    

    my_functions.cpp

    #include "my_header.h"
    #include <iostream>
    using namespace std;
    
    void function()
    {
     cout<<"ok";
    }
    
    void function_2()
    {
     cout<<"function_2";
    }
    


  • pumuckl schrieb:

    1. Die Definition muss in C-Code nicht weiter markiert werden, in C++-Code muss sie auch wieder als extern "C" markiert werden.

    Edit: Wobei ... bei mir läuft das Programm fehlerfrei und ohne Warnungen beim Erstellen:

    cl -c main.c
    cl -c /EHsc my_functions.cpp
    link main.obj my_functions.obj

    erstellt main.exe ohne Warnungen und Fehler ...



  • externC schrieb:

    Wieder die Prototyp Fehlermeldung. 😞

    Ich versteh nicht was da jetzt schon wieder falsch sein soll. (Naja falsch vielleicht nicht denn es Kompiliert ja und läuft. (Ein Lehrer sagte mal "Das sind nur Warnungen das ist nicht so schlimm", aber ob das nicht so schlimm ist da zweifel ich irgendwie dran, den die Warnung wird ja nicht zum Spass ausgegeben.)

    Das ist richtig. Zum Spaß sind die nicht da. Diese Warnung richtig interpretiert heißt: "Ich kann nicht überprüfen, ob es die Funktion gibt und/oder ob Du sie mit den richtigen Parametern aufrufst". Du bist also auf Dich allein gestellt und wenn Du etwas falsch machst, dann gibt Dir das Programm Grütze aus oder schmiert ab.

    externC schrieb:

    my_header.h

    #ifndef my_header
    #define my_header
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    void function();
    void function_2();
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    

    Du solltest für eigene Macros immer Namen verwenden, die mit einem Großbuchstaben anfangen und keine kleinen Buchstaben enthalten. Auch übermäßiger Gebrauch von Unterstrichen (am Anfang oder irgendwo zweimal hintereinander) sollte man für eigene Namen nicht verwenden, da die reserviert sind.

    Der Haken hier ist, dass eine leere Parameter-Klammer in C90 etwas anderes bedeutet als in C++:

    In C90 wird hier dem Compiler lediglich gesagt, dass es da zwei Funktionen gibt, mit den Namen function und function_2. Welche Parameter die bekommen ist aber offen. Möchtest Du dem Compiler mitteilen, dass die Funktionen keine Parameter bekommen, musst Du ein void in die Klammern schreiben:

    void function(void);
    void function_2(void);
    

    In C++ ist das void überflüssig. Man hielt es beim Design von C++ für eine ziemlich dämliche Idee, die Angabe über Parameter offen zu lassen. Dementsprechend verhält sich eine leere Klammer in C++ genauso wie eine in C mit void drin. In C++ ist das void aber auch nicht falsch oder schädlich. Aus C-Kompatibilitätsgründen ist es in C++ immer noch erlaubt. In reinem C++ Code solltest du void an dieser Stelle nicht verwenden, da das einfach unüblich ist.

    Versuch's also mal mit void in der Klammer.



  • Danke an alle für die Hilfe, jetzt funktioniert es, hier nochmal alle Programme vielleicht kann wer anderes damit auch noch was Anfangen. Ich hab bei wikipedia auch noch 2 interessante Links gefunden:

    http://en.wikipedia.org/wiki/Compatibility_of_C_and_C%2B%2B
    http://en.wikipedia.org/wiki/Name_mangling

    Die C++ Version:

    main.cpp

    #include <iostream>
    #include "my_header.h"
    
    using namespace std;
    
    int main(int argc, char* argv[])
    {
    
     check_if_file_exists ();
    
    system("PAUSE");
            return 0;
    }
    

    my_header.h

    #ifndef my_header 
     #define my_header 
    
     /*/
     __cplusplus wird automatisch vom Compiler definiert, wenn ein C++ Compiler verwendet wird
     (Ist im C++ Standart so festgelegt)
     /*/
    
     #ifdef __cplusplus // Wenn kein C++ Compiler verwendet wird, dann wird void check_if_file_exists(); ganz normal aufgerufen
    
     extern "C" { // Wenn ein C++ Compiler verwendet wird dann wird die Funktion check_if_file_exists();
                // mit den C Symbolnamen Compiliert  http://en.wikipedia.org/wiki/Compatibility_of_C_and_C%2B%2B
    			// Weiteres Stichwort: "name mangling"  http://en.wikipedia.org/wiki/Name_mangling
     #endif 
    
     void check_if_file_exists();
    
     #ifdef __cplusplus // Falls ein C++ Compiler verwendet wurde dann wird hier die Klammer vom exter "C" Befehl geschlossen.
     } 
     #endif 
     #endif
    

    my_functions.c

    #include "my_header.h"
    #include <iostream>
    #include <fstream>
    
    void check_if_file_exists()
    {
    
            std::ifstream file ("test.txt");
    
            if ( file == NULL )
            {
                    std::cout<<"Die Datei test.txt existiert nicht\n"<<std::endl;
            }
    
            else
            {
                    std::cout<<"test.txt existiert"<<std::endl;
            }
    
    }
    

    Und jetzt die C Version

    main.c

    #include <stdio.h>
    #include "my_header.h"
    
    int main()
    {
    
    check_if_file_exists();
    
    system("PAUSE");
    return 0;
    
    }
    

    my_header.h

    #ifndef my_header 
    #define my_header
    
    #ifdef __cplusplus // Wenn kein C++ Compiler verwendet wird, dann wird void check_if_file_exists(); ganz normal aufgerufen
    
    extern "C" {   // Wenn ein C++ Compiler verwendet wird dann wird die Funktion check_if_file_exists();
                // mit den C Symbolnamen Compiliert  http://en.wikipedia.org/wiki/Compatibility_of_C_and_C%2B%2B
                // Weiteres Stichwort: "name mangling"  http://en.wikipedia.org/wiki/Name_mangling
    #endif
    
     void check_if_file_exists(void); // Wenn aus C eine C++ Funktion aufgerufen werden soll,
                                      // und die C++ Funktion keine Parameter erwartet dann muss
                                      // der Übergabeparameter void sein, das void muss man nur hier
                                      // in my_header.h schreiben
    
     #ifdef __cplusplus // Falls ein C++ Compiler verwendet wurde dann wird hier die Klammer vom exter "C" Befehl geschlossen.
     } 
     #endif 
     #endif
    

    my_functions.cpp

    #include "my_header.h"
    #include <iostream>
    #include <fstream>
    
    void check_if_file_exists()
    {
    
            std::ifstream file ("test.txt");
    
            if ( file == NULL )
            {
                    std::cout<<"Die Datei test.txt existiert nicht\n"<<std::endl;
            }
    
            else
            {
                    std::cout<<"test.txt existiert"<<std::endl;
            }
    
    }
    


  • #include <stdio.h>
    #include "my_header.h"
    
    int main()
    {
    
    check_if_file_exists();
    
    system("PAUSE");
    return 0;
    
    }
    

    Schöner:

    #include <cstdio>//Benutze die C++-Version dieses Headers
    #include "my_header.h"
    
    int main()
    {
        check_if_file_exists();
        for(;;);//return-Statement eig. unnötig, es wird Standardmäßig 0 zurückgegeben (Achtung, nur bei main()!)
    }//system("pause"); ist unportabler Blödsinn. Nimm lieber eine Endlosschleife
    

    Edit: Und brav auf Formattierung achten!



  • Wieso gibt es denn jetzt 2mal eine my_header.h-Datei (Einmal im Abschnitt "C++-Version" und einmal im Abschnitt "C-Version")? Kann das nicht jedes mal dieselbe sein? Die Headerdatei definiert eine C-Schnittstelle. Auf welcher Seite welche Sprache verwendet wird, ist dann ja eigentlich egal, sofern man dort den __cplusplus-Trick eingebaut hat.

    Dein IncludeGuard besteht wieder aus Kleinbuchstaben.



  • Hacker schrieb:

    //system("pause"); ist unportabler Blödsinn. Nimm lieber eine Endlosschleife
    

    Super Alternative 🙄



  • @Hacker: Du hast echt ein komisches Verständnis von Schönheit. Die CPU-Resourcen-verschwendende Tu-Gar-Nichts-Schleife geht ja mal gar nicht!


  • Mod

    Hacker schrieb:

    // Nimm lieber eine Endlosschleife
    

    Das ist undefinierter Blödsinn.



  • Gut, Vorschlag:

    std::cin.get();
    

  • Mod

    Immer noch nicht gut. Wir haben hier eine FAQ, falls du es noch nicht wusstest.



  • Und was spricht gegen system("pause") wenn er auf seinem Windows-Rechner spielt?
    Bezweifle dass seine Spielereien jemals ernsthafte Software werden, die er portieren möchte.



    Ethon__ schrieb:

    Und was spricht gegen system("pause") wenn er auf seinem Windows-Rechner spielt?
    Bezweifle dass seine Spielereien jemals ernsthafte Software werden, die er portieren möchte.

    @SeppJ: Ja, ich weiß dass es hier eine FAQ gibt.
    Da steht aber auch nichts großartig anderes drinnen.


  • Mod

    Hacker schrieb:

    @SeppJ: Ja, ich weiß dass es hier eine FAQ gibt.
    Da steht aber auch nichts großartig anderes drinnen.

    Und ob da was anderes drinsteht. Da steht nämlich kein einziger deiner Unsinnsvorschläge.



  • void wait ()
    {
        std::cin.clear();
        std::cin.ignore(cin.rdbuf()->in_avail());
        std::cin.get();
    }
    

    Diese Funktion verfeinert nur, was ich mit std::cin.get() bereits vorschlug. Und ist nebenbei die erste vorgeschlagene Alternative.


Anmelden zum Antworten