Etwas verwirrt mit Headerdateien und weiterreichen von Variablen/Strings



  • included hatte ich das schon, deswegen habe ich mich gewundert, wo mein Fehler her kam. Den Rest deiner Antwort muss ich jetzt mal in Ruhe durchgehen 🙂



  • Ich glaube ich komme der Sache näher 🙂

    - ich habe die math.h included in form1.h (hatte ich vorher schon) und diese beiden Zeilen habe ich ebenfalls übernommen:

    #include <msclr\marshal_cppstd.h>
    using namespace msclr::interop;

    - was genau macht marshal_as - ich habe ein wenig nachgegoogelt und gefunden, dass es für native/managed Variablen und dem herumwechseln damit zu tun hat - wann ist mein "uebergabe_string_1" managed, wann ist er native?

    - kann ich generell wenn ich eine funktion habe immer Variablen aus verschiedenen Namespaces verwenden, indem ich

    namespacename::variablenname

    verwende, anstelle von

    using namespacename;

    und dann gilt es für die ganze Funktion? Oder genauer gefragt, unterscheidet der Compiler (korrekt) zwischen

    namespacename1::Variable1

    und

    namepspacename2::Variable1

    ?

    Jetzt bekomme ich beim Ausführen folgenden Fehler:

    1> calc.cpp
    1>v3.obj : error LNK2028: Nicht aufgelöstes Token (0A000021) ""void __clrcall diese_und_jene_Variable::aendern(void)" (?aendern@diese_und_jene_Variable@@$$FYMXXZ)", auf das in Funktion ""private: void __clrcall v3::Form1::mach_was_Click(class System::Object ^,class System::EventArgs ^)" (?mach_was_Click@Form1@v3@@$$FAAAMXPAAMXPAAVObject@System@@PAAVEventArgs@4@@Z)" verwiesen wird. 1>v3.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""void \_\_clrcall diese\_und\_jene\_Variable::aendern(void)" (?aendern@diese\_und\_jene\_Variable@@FYMXXZ)"inFunktion""private:void__clrcallv3::Form1::mach_was_Click(classSystem::Object,classSystem::EventArgs)"(?mach_was_Click@Form1@v3@@FYMXXZ)" in Funktion ""private: void \_\_clrcall v3::Form1::mach\_was\_Click(class System::Object ^,class System::EventArgs ^)" (?mach\_was\_Click@Form1@v3@@FAFAAAMXPAAVObject@System@@PAAVObject@System@@PAAVEventArgs@4@@Z)".
    1>C:\Users...exe : fatal error LNK1120: 2 nicht aufgelöste externe Verweise.

    Hier meine Dateien:

    calc.cpp

    #include "stdafx.h"
    #include <sstream>
    #include <string>
    #include <cmath>
    #include "calc.h"
    
    using namespace std;
    
    namespace diese_und_jene_Variable	{
    
    	// Anfangswerte festsetzen
    
    	int block_whs = 0;
    	int block_abstand = 0;
    	int zeichen_anz = 0;
    	std::string uebergabe_string_1;
    }
    
    void aendern()	{
    	diese_und_jene_Variable::uebergabe_string_1 = "Test erfolgreich!"; 
    
    };
    

    calc.h:

    #pragma once
    
    #ifndef CALC_H
    #define CALC_H
    
    #include <string>
    
    namespace diese_und_jene_Variable	{
    
    	extern int block_whs;
    	extern int block_abstand;
    	extern int zeichen_anz;
    	extern std::string uebergabe_string_1;
    
    void aendern(); 
    }
    
    #endif
    

    form1.h (auszugsweise):

    #pragma once
    #include "calc.h"
    #include <msclr\marshal_cppstd.h>
    using namespace msclr::interop; 
    namespace v3 {
    
    	using namespace System;
    	using namespace System::IO;
    	using namespace System::ComponentModel;
    	using namespace System::Collections;
    	using namespace System::Windows::Forms;
    	using namespace System::Data;
    	using namespace System::Drawing;
    
    	/// <summary>
    	/// Zusammenfassung für Form1
    	/// </summary>
    .
    .
    .
    .
    
    private: System::Void richTextBox1_TextChanged_1(System::Object^  sender, System::EventArgs^  e) {
    		 }
    private: System::Void mach_was_Click(System::Object^  sender, System::EventArgs^  e) {
    
    			//erstellt einen String vom Typ system::String^ 
    			String^ Inhalt_richTextBox1 = richTextBox1->Text;
    
    			//Konvertiert den String in das Format std::string
    			diese_und_jene_Variable::uebergabe_string_1 = marshal_as<std::string>(Inhalt_richTextBox1); 
    
    			//Funktionsaufruf
    			diese_und_jene_Variable::aendern();
    
    			//Konvertierung von std::string zurück in System::string und Ausgabe in der richTextBox1
    			richTextBox1->Text = gcnew String(diese_und_jene_Variable::uebergabe_string_1.c_str()); 
    
    			 }
    private: System::Void Form1_Load(System::Object^  sender, System::EventArgs^  e) {
    		 }
    };
    }
    


  • Ich fürchte ich habe deinen Punkt 2 nur bruchstückhaft befolgt *ascheaufmeinhaupt*.

    Wenn ich nun also der Funktion aendern den String aus richTextBox1 übergeben will, muss ich sie mit

    std::String Funktionsname(std::String Stringname1, std::String Stringname2 ...);
    

    aufrufen. Dann muss ich aber in der calc.h sie erst nach dem namespace definieren, in den Namespace müssen Stringname1 und Stringname2 nicht hinein, sehe ich das richtig?

    Noch eine weitere Frage habe ich: Kann man generell sagen, dass alles was ich zum rechnen verwende immer std:: sein muss und alles was aus einer Form kommt immer System:: ist?



  • Ich glaube ich komme der Sache näher

    Da bin ich mir nicht so sicher... 🕶

    Es soll gesagt sein: Benutze cmath anstatt math.h.

    - was genau macht marshal_as - ich habe ein wenig nachgegoogelt und gefunden, dass es für native/managed Variablen und dem herumwechseln damit zu tun hat - wann ist mein "uebergabe_string_1" managed, wann ist er native?

    Genau, es konvertiert zwischen managed (C++/CLI) und native (C++). System::String ist managed, std::string ist native.

    - kann ich generell wenn ich eine funktion habe immer Variablen aus verschiedenen Namespaces verwenden, indem ich...

    Ja. Das gilt nicht nur für Variablen, sondern für Klasse, Structs, Funktionen...

    und dann gilt es für die ganze Funktion? Oder genauer gefragt, unterscheidet der Compiler (korrekt) zwischen...

    Ja. Das sind zwei unterschiedliche Variablen.

    Jetzt bekomme ich beim Ausführen folgenden Fehler: ...

    Nicht beim Ausführen, sondern beim Linken. Das kommt daher, dass Du die Funktion aendern(..) im Namespace diese_und_jene_Variable deklariert, aber im globablen NS definiert hast. Der Linker findet die Definition der Funktion nicht!

    Noch eine weitere Frage habe ich: Kann man generell sagen, dass alles was ich zum rechnen verwende immer std:: sein muss und alles was aus einer Form kommt immer System:: ist?

    Kann man sagen wenn man will. Könnte man so als Daumenregel halten.

    Hier noch eine korrigierte Fassung deines Codes.

    In Form1.h

    private: System::Void mach_was_Click(System::Object^  sender, System::EventArgs^  e) {
    
            std::string text = marshal_as<std::string>(richTextBox1->Text); 
            std::string resultat = diese_und_jene_Variable::aendern(text);
            richTextBox1->Text = gcnew String(resultat.c_str());
        }
    

    calc.h

    #pragma once
    
    #include <string>
    
    namespace diese_und_jene_Variable
    {
        std::string aendern(const std::string& text); 
    }
    

    calc.cpp

    #include "stdafx.h"
    #include "calc.h"
    
    namespace diese_und_jene_Variable
    {
        std::string aendern(const std::string& text)
        {
            return "Test erfolgreich: " + text;
        };
    }
    

    Irgendwie ist das ziemlich hoffnungslos - es fehlen die Grundlagen, aber ganz krass.

    Edit:
    a.) Ich hoffe Du hast bemerkt, dass keine globale Variable (std::string Inhalt_richTextBox1;) nötig ist.
    b.) Das Argument bei der Funktion aendern(..) als const & zu Übergeben erspart eine Kopie (nur als Hinweis).



  • Ja, das bemerke ich auch gerade. Ich dachte mir circa vor ein paar Tagen noch sowas wie "Wie schwer kann es sein, deine ganzen Fortran Codes in Visual umzuschreiben..." 🙂

    Werd mich weiter durchackern, danke für deine Hilfe soweit!



  • Noch eine Frage: Warum cmath statt math.h?



  • Edith: ich hatte eh cmath - oder meintest du es andersrum? Lieber math.h?



  • conqueror24 schrieb:

    Edith: ich hatte eh cmath - oder meintest du es andersrum? Lieber math.h?

    Lieber cmath weil Standard.



  • Kann ich das getrost vergessen (Kein Fehler, ein Warning)?

    Warnung	1	warning C4101: 'ex': Unreferenzierte lokale Variable	c:\users\ra\desktop\vigenere\vigenere\v3\Form1.h	185
    

    Das kommt von der Zeile:

    catch(Exception^ ex)	{MessageBox::Show("Datei unlesbar"); }
    

    Oder gibt es einen guten Grund, warum ich die Warnung nicht einfach übergehen sollte 🙂



  • Noch eine Frage zu dem Punkt von vorher:

    calc.h

    namespace ns1	{
    	std::string irgendeinstring2(const std::string& irgendeinstring1);
    	}
    

    calc.cpp:

    namespace ns1	{ irgendeinevariable = 0;
    	std::string funktionsname(const std::string& Inhalt_rTB1)	{	
    	ns1::irgendeinevariable1 = ...
    return irgendeinevariable1};
    }
    

    und alternativ:

    calc.cpp:

    namespace ns1	{ irgendeinevariable = 0; };
    
    std::string funktionsname(const std::string& Inhalt_rTB1)	{	
    	using namespace ns1;
    	irgendeinevariable1 = 5;
    return irgendeinevariable1};
    

    Ich finde es irgendwie komisch immer in einem Namespace zu arbeiten? Oder soll das so sein und mein Gefühl betrügt mich? Warum muss ich, obwohl ich innerhalb der {} des Namespaces bin ihn dann noch immer mit namespacenamen:: vor die Variablen setzen?



  • conqueror24 schrieb:

    Kann ich das getrost vergessen (Kein Fehler, ein Warning)?

    Warnung	1	warning C4101: 'ex': Unreferenzierte lokale Variable	c:\users\ra\desktop\vigenere\vigenere\v3\Form1.h	185
    

    Das kommt von der Zeile:

    catch(Exception^ ex)	{MessageBox::Show("Datei unlesbar"); }
    

    Ja, kannst Du. Oder noch besser Du behebst sie, z.B. so:

    catch(Exception^)	{MessageBox::Show("Datei unlesbar"); }
    

    Irgendwie scheint mir in deinem Bsp. der Funktionsname irgendeinstring2 schlecht gewählt. Hältst Du irgendeinstring2 für eine Variable? Das ist es nicht, es ist eine Funktion!

    Ich finde es irgendwie komisch immer in einem Namespace zu arbeiten

    Dann lass es. Namespaces sind wie gesagt ein Mechanismus um zu strukturieren und um Nameskonflikte zu vermeiden. In kleinen Programmen spielt das nicht so eine Rolle.

    Warum muss ich, obwohl ich innerhalb der {} des Namespaces bin ihn dann noch immer mit namespacenamen:: vor die Variablen setzen?

    Das musst Du nicht. Wenn doch, machst Du was falsch.

    Lass endlich die globalen Variablen weg - Du brauchst sie nicht! Übergib alles nötige als Parameter und gib falls nötig einen Wert zurück. Die Funktionen sollen möglichst keine Seiteneffekte haben (wie z.B. eine globale Variable ändern).



  • Ja du hast (natürlich) recht, da habe ich mich ein wenig verlesen (oder so halb, weil ich noch einen zweiten Namespace verwendet hatte im ersten). Und ja, das war ein dumm getaufter Funktionsname.

    Du meinst also (dein Beispiel hier nochmal, weil ich es so verwendet habe)

    private: System::Void mach_was_Click(System::Object^  sender, System::EventArgs^  e) {
    
            std::string Inhalt_richTextBox1 = marshal_as<std::string>(richTextBox1->Text);
            std::string resultat = namespacename::Funktionsname(Inhalt_richTextBox1);
            richTextBox1->Text = gcnew String(resultat.c_str()); }
    

    Wenn ich nun aber nicht

    namespacename::Funktionsname(Inhalt_richTextBox1)
    

    mache, wie bekomme ich dann den Inhalt von meiner TextBox dahin, wo ich damit herumrechnen/arbeiten kann? Also sprich in die calc.cpp Datei?



  • conqueror24 schrieb:

    Wenn ich nun aber nicht

    namespacename::Funktionsname(Inhalt_richTextBox1)
    

    mache, wie bekomme ich dann den Inhalt von meiner TextBox dahin, wo ich damit herumrechnen/arbeiten kann? Also sprich in die calc.cpp Datei?

    Auch als Argumente von Funktionen - die argumente können auch weitergereicht werden.



  • Darf ich das dann so machen?

    form1.h

    std::string Inhalt_rTB1 = marshal_as<std::string>(richTextBox1->Text);
    richTextBox2->Text = gcnew String(funktionsname(Inhalt_rTB1).c_str());
    


  • conqueror24 schrieb:

    Darf ich das dann so machen?

    form1.h

    std::string Inhalt_rTB1 = marshal_as<std::string>(richTextBox1->Text);
    richTextBox2->Text = gcnew String(funktionsname(Inhalt_rTB1).c_str());
    

    Ja. 🙂


Anmelden zum Antworten