Mal wieder die globalen Variablen!



  • Hallo,

    ich hoffe ich nerve damit niemanden, aber ich habe mal wieder ein Problem mit den globalen Variablen und diese richtig einzubinden.

    Ich habe schon verschiedene Beiträge in diesem Forum dazu gefunden, bin aber mein Problem trotzdem nicht los.

    Also ich binde meine globalen Variablen in stdafx.h ein mit

    namespace Global{
    	extern float fOSPTol, fUSPTol, fODWTol, fUDWTol;
    	extern char nMess;
    }
    

    Der Zugriff in meinem Hauptdialog:

    void CSerial_09Dlg::OnBnClickedButtonMessEin()
    {
    	// TODO: Fügen Sie hier Ihren Kontrollbehandlungscode für die Benachrichtigung ein.
    	SendData(0,'A'); // 'A' für Automatikmodus
    	GetDlgItem(IDC_BUTTON_MESS_EIN)->EnableWindow(FALSE);
    	GetDlgItem(IDC_BUTTON_MESS_AUS)->EnableWindow(TRUE);
    
    	char* strStepsOSPTol = new char[5];
    	char* strStepsUSPTol = new char[5];
    	char* strStepsODWTol = new char[5];
    	char* strStepsUDWTol = new char[5];
    
    	// Toleranzen in Schritte umrechnen
    	int nStepsOSPTol = Global::fOSPTol / 0.0025;
    	int nStepsUSPTol = Global::fUSPTol / 0.0025;
    	int nStepsODWTol = Global::fODWTol / 0.0025;
    	int nStepsUDWTol = Global::fUDWTol / 0.0025;
    
    	sprintf(strStepsOSPTol, "%d",nStepsOSPTol);
    	sprintf(strStepsUSPTol, "%d",nStepsUSPTol);
    	sprintf(strStepsODWTol, "%d",nStepsODWTol);
    	sprintf(strStepsUDWTol, "%d",nStepsUDWTol);
    
    	// Toleranzen senden
    	SendData(0,strStepsOSPTol,4);
    	SendData(0,strStepsUSPTol,4);
    	SendData(0,strStepsODWTol,4);
    	SendData(0,strStepsUDWTol,4);
    
    	// Mess-Methodik senden
    	SendData(0,Global::nMess);
    
    	// Timer starten
    	int Probe = SetTimer(1,200,NULL);
    	if (Probe == 0){
    		AfxMessageBox(_T("Timer konnte nicht initialisiert werden"),MB_OK | MB_ICONINFORMATION,0);
    	}
    
    }
    

    Der Zugriff aus meinem Dialog für Einstellungen:

    void CEinstellungen::OnBnClickedOk()
    {
    	// TODO: Fügen Sie hier Ihren Kontrollbehandlungscode für die Benachrichtigung ein.
    	// 1. CArray mit den übernommenen Werten global zugänglich speichern
    	// 2. (float-Werte)
    
    	Global::fOSPTol = _wtof(m_strOSPTol);
    	Global::fUSPTol = _wtof(m_strUSPTol);
    	Global::fODWTol = _wtof(m_strODWTol);
    	Global::fUDWTol = _wtof(m_strUDWTol);
    
    	if (strMessMethode == _T("Oeffner")){
    		Global::nMess = 'O';
    	}
    	else if (strMessMethode == _T("Schliesser")){
    		Global::nMess = 'S';
    	}
    	else if (strMessMethode == _T("Wechsler")){
    		Global::nMess = 'W';
    	}
    
    	CDialog::OnOK();
    }
    

    Ich habe es jetzt zweimal compilieren können und es hat funktioniert, d.h. ohne LNK-error.

    Jetzt habe ich heute mein Projekt "neu erstellt" und ich bekomme wieder jede Menge dieser LNK-error.

    Einstellungen.obj : error LNK2001: Nicht aufgelöstes externes Symbol ""char Global::nMess" (?nMess@Global@@3DA)".
    Serial_09Dlg.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""char Global::nMess" (?nMess@Global@@3DA)" 
    in Funktion ""public: void __thiscall CSerial_09Dlg::OnOptionenReferenz(void)" (?OnOptionenReferenz@CSerial_09Dlg@@QAEXXZ)".
    Einstellungen.obj : error LNK2001: Nicht aufgelöstes externes Symbol ""float Global::fUDWTol" (?fUDWTol@Global@@3MA)".
    Serial_09Dlg.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""float Global::fUDWTol" (?fUDWTol@Global@@3MA)" 
    in Funktion ""public: void __thiscall CSerial_09Dlg::OnOptionenReferenz(void)" (?OnOptionenReferenz@CSerial_09Dlg@@QAEXXZ)".
    Einstellungen.obj : error LNK2001: Nicht aufgelöstes externes Symbol ""float Global::fODWTol" (?fODWTol@Global@@3MA)".
    Serial_09Dlg.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""float Global::fODWTol" (?fODWTol@Global@@3MA)" 
    in Funktion ""public: void __thiscall CSerial_09Dlg::OnOptionenReferenz(void)" (?OnOptionenReferenz@CSerial_09Dlg@@QAEXXZ)".
    Einstellungen.obj : error LNK2001: Nicht aufgelöstes externes Symbol ""float Global::fUSPTol" (?fUSPTol@Global@@3MA)".
    Serial_09Dlg.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""float Global::fUSPTol" (?fUSPTol@Global@@3MA)" 
    in Funktion ""public: void __thiscall CSerial_09Dlg::OnOptionenReferenz(void)" (?OnOptionenReferenz@CSerial_09Dlg@@QAEXXZ)".
    Einstellungen.obj : error LNK2001: Nicht aufgelöstes externes Symbol ""float Global::fOSPTol" (?fOSPTol@Global@@3MA)".
    Serial_09Dlg.obj : error LNK2001: Nicht aufgelöstes externes Symbol ""float Global::fOSPTol" (?fOSPTol@Global@@3MA)".
    

    Ich habe, wie bereits erwähnt, einige Beiträge durchforstet und auch den Hinweis gefunden in den Projekteinstellungen etwas zu ändern:
    Stichwort: /INCREMENTAL durch /FORCE ersetzen in den Linkereinstellungen.
    Wenn ich das versuche wird die Änderung allerdings nicht übernommen und somit nicht wirksam.

    Weiß jemand wie ich das sonst lösen kann.

    Stichwort: Get und Set-Methoden?
    Ich müsste auf Variablen aus der Dialogklasse für Einstellungen in meinem Hauptdialog zugreifen. Nur habe ich das Gefühl, dass die Lebensdauer der Variablen in meinem Einstellungsdialog abgelaufen ist sobald ich den Einstellungs-Dialog schliesse.

    Gruss

    Oliver



  • Erstens: 'extern' sagt dem Compiler nur, daß es diese Variablen gibt - in (genau) einer der Quelldateien mußt du auch die zugehörigen Definitionen unterbringen.

    Zweitens: globale Variablen sind "böse". Das heißt, du solltest die Variablen lieber in eine deiner Klassen packen (ich würde den Hauptdialog verwenden).

    PS: Die Methode OnBnClickedButtonMessEin() hat übrigens ein gewaltiges Speicherleck - du reservierst 4*5 Byte auf dem Heap und räumst die nirgends wieder auf.


  • Mod

    Den Ausführungen von CStoll kann ich mich nur anschließen.

    Wenn Du so etwas wie globale statische Variablen benötigst, dann solltest Du das in Singletons verpacken oder einfach schon bestehende Singletons verwenden (CWinApp).



  • Danke für den Hinweis mit dem Speicherlek!

    Ich bin MFC-C++ Neuling und dazu Quereinsteiger. Du meinst sicher die char-Arrays
    oder?
    Soll ich den Speicher mit "delete" wieder freigeben?

    Du sagst ich sollte die Variable lieber in eine meiner Klassen packen. Das habe ich bereits probiert. Nur sobald ich mein Eistellungs-Dialog verlasse möchte ich Werte aus eben diesem Dialog in meinem Hauptdialog abspeichern, damit ich die Werte in meinem Hauptdialog nutzen kann. Nur funktioniert das leider nicht.

    Ich habe die Variablen in meiner Klasse CEinstellungen im Header wie folgt deklariert:

    public:
    	float fOSPTol, fUSPTol, fODWTol, fUDWTol;
    	char nMess;
    

    In der Routine, in der ich den Einstellungs-Dialog beende habe ich folgendes deklariert:

    void CEinstellungen::OnBnClickedOk()
    {
    	// TODO: Fügen Sie hier Ihren Kontrollbehandlungscode für die Benachrichtigung ein.
    	// 1. CArray mit den übernommenen Werten global zugänglich speichern
    	// 2. (float-Werte)
    
    	fOSPTol = _wtof(m_strOSPTol);
    	fUSPTol = _wtof(m_strUSPTol);
    	fODWTol = _wtof(m_strODWTol);
    	fUDWTol = _wtof(m_strUDWTol);
    
    	if (strMessMethode == _T("Oeffner")){
    		nMess = 'O';
    	}
    	else if (strMessMethode == _T("Schliesser")){
    		nMess = 'S';
    	}
    	else if (strMessMethode == _T("Wechsler")){
    		nMess = 'W';
    	}
    
    	Set();
    
    	CDialog::OnOK();
    }
    
    void CEinstellungen::OnOK()
    {
    	;
    }
    
    void CEinstellungen::Set()
    {
    	CSerial_09Dlg pMyDlg = new CSerial_09Dlg;
    	pMyDlg.fOSPTol = fOSPTol;
    	pMyDlg.fUSPTol = fUSPTol;
    	pMyDlg.fODWTol = fODWTol;
    	pMyDlg.fUDWTol = fUDWTol;
    
    	pMyDlg.nMess = nMess;
    
    	delete pMyDlg; // Hier gebe ich den Speicherbereich wieder frei, richtig?
    }
    

    CSerial_09Dlg ist meine Hauptdialogklasse, in dieser habe ich ebenfalls intern die Variablen:

    public:
    	float fOSPTol, fUSPTol, fODWTol, fUDWTol;
    	char nMess;
    

    deklariet.

    Wenn ich also meinen Einstellungs-Dialog verlasse müssten die Variablen doch bekannt sein oder nicht?
    Im Debug-Modus musste ich jedoch feststellen, das dies nicht der Fall war.

    Ich weiß nicht mehr weiter!

    Bitte um Hilfe

    Oliver



  • Was ist im übrigen ein Singleton?

    Oliver



  • oliher schrieb:

    Was ist im übrigen ein Singleton?

    Oliver

    Ein Design Pattern, deutsch Entwurfsmuster. Siehe auch:
    http://de.wikipedia.org/wiki/Entwurfsmuster
    http://www.dofactory.com/Patterns/Patterns.aspx
    http://www.dofactory.com/Patterns/PatternSingleton.aspx



  • Problem gelöst!

    Ich habe mir ne globale Datenklasse geschrieben!

    Oliver



  • oliher schrieb:

    Danke für den Hinweis mit dem Speicherlek!

    Ich bin MFC-C++ Neuling und dazu Quereinsteiger. Du meinst sicher die char-Arrays
    oder?
    Soll ich den Speicher mit "delete" wieder freigeben?

    Das ist eine Möglichkeit. Aber besser ist es wohl, du verwendest std::string's (in deiner Anwendung könnten auch lokale char-Arrays ausreichen.

    Du sagst ich sollte die Variable lieber in eine meiner Klassen packen. Das habe ich bereits probiert. Nur sobald ich mein Eistellungs-Dialog verlasse möchte ich Werte aus eben diesem Dialog in meinem Hauptdialog abspeichern, damit ich die Werte in meinem Hauptdialog nutzen kann. Nur funktioniert das leider nicht.

    Wie ich schon sagte, ist vermutlich der Hauptdialog besser beeignet. Allerdings solltest du zum Setzen nicht eine neue Instanz des Hauptdialogs anlegen (deine Methode Set() legt ein neues Objekt an, schreibt die Daten dort rein und löscht es wieder - inklusive der gerade geschriebenen Daten), sondern dir über AfxGetMainWnd() das vorhandene Hauptfenster deiner Anwendung holen.

    PS: Daß der Ausschnitt kompiliert wurde, wundert mich. pMyDlg ist (trotz des Namens) kein Zeiger und kann und muss deshalb nicht per new angelegt werden (nein, wir sind hier nicht bei Java).


Log in to reply