Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » VC++ / MFC » Grenzen der Programmierung

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
20.07.2004, 08:27 Uhr
Groovejuice



Hallo,
ich hab mal ne frage an einige Experten. Ich arbeite grade an einem Programm mit Visual C++ 6.0. Es hat schon einen gewissen Umpfang erreicht.

Wenn aber grade dabei bin neue Programmteile hinzuzufügen so treten Fehler auf die gar keine sind. z.B speichere ich unter anderem Pfadnamen in einigen CStrings, diese werden mittem im Programmablauf gelöscht, oder einige Dialogfelder gehen gar nicht mehr auf und ein Assertion fehler kommt.

Bin ich da an die Grenze des programmierens gekommmen und vorhandene variablen werden aus Speichermangel einfach überschrieben oder kommt einfach das Visual Studio mit grossen Anwendungen nicht klar ?

Ich habe auch noch ne 2. Anwendung in welcher einige verschachtelte Strukturen Daten speichern. Mitten im Programmablauf kommt dann die
Nachricht Stack Overflow.
Wenn man eine hohe Programmiersprache benutzt sollte man sich eigentlich nicht um solche Probleme kümmern müssen sonst kann man ja ach gleich in Assembler programmieren.

Wie kann man frühzeitig solche Probleme erkennen und beheben ?

Mfg Thomas
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
20.07.2004, 08:58 Uhr
Tommix



Hallo,
ich bin zwar kein Experte, kenne aber die Problematik.
Es geht hier wohl eher um die Grenzen des Programmierers, als die der Programmierung. Die "Fehler, die keine sind" sind nach meiner Erfahrung sehr wohl welche. Es ist nur ab einem gewissen Programmumfang einfach so, dass man Fehler nicht mehr durch bloßes hingucken erkennt. Wenn man undiszipliniert programmiert, können Situationen im Programmablauf entstehen, die in 99% aller Fälle gut gehen. In einem großem, komplexen Programm tritt dann irgenwann das eine Prozent auf.
Deshalb:
- Code in Module zergliedern, die voneinander unabhängig sind so gut es geht.
- Niemals annehmen, dass eine bestimmte Situation schon nicht eintreten wird.
- Testen, testen, testen.
- Der Debugger sieht alles - also benutze ihn.
- Zuerst das Programmkonzept überlegen, nicht gleich loscodieren.
Das klingt vielleicht etwas nach Klugscheisserei, aber ich weiss selbst, was es heisst in einem vermeintlich fertigem Programm nach dubiosen Fehlern zu suchen.

Gruss, Tommix
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
21.07.2004, 11:02 Uhr
~Groovejuice
Gast


Hmm,
klar benutz ich den Debugger.
Ich will hier mal ein Beispiel nennen.

Dies ist Klasse meines Hauptdialogfeldes


C++:
typedef struct Pfade
{
    CString HauptPfadname;
    CString ProjektPfad;
    CString SoundPfad;
}Pfade;

#include "stdafx.h"
#include "CaTSo.h"
#include "FileTrans.h"
#include "CanCon.h"
#include "CaTSoDlg.h"
#include <string>
#include <Shellapi.h>
#include <windows.h>
using namespace std;
#include "Filter_Set.h"
#include "Signal_Set.h"
#include "DirDialog.h"

class CCaTSoDlg : public CDialog // CBitmapDialog
{
    BOOL einmal[10];
    Pfade PfadN;
    SendMess SndPuff;
    int m_iGang;
    BOOL    m_bKompAus;
    double    m_fdGangKonst [6];
    TCANMsg FunkKomp[25];
    DWORD Zeit;

    BOOL running;

    // Konstruktion
    Bilder Bmp;

    int m_iWert_Gas;
    int m_iWert_Dreh;
    int m_iWert_Master;
    CSockCom SockKom;

public:
    TachoZeiger    m_dTacho;
    RECT m_recDrehZRec, m_recSpeedRec;
    CWnd *m_hMainWin;
    void DisplayMessage(int);
    CCaTSoDlg(CWnd* pParent = NULL);    // Standard-Konstruktor
    ~CCaTSoDlg();                        // Destruktor

    CJoyCon JoyIn;                        // Klasse Joystick
    
    FilSig FiSi;
    
    CanMsg CanDaF;

    JoyKnopf KnopfList;
    
// Dialogfelddaten
    //{{AFX_DATA(CCaTSoDlg)
    enum { IDD = IDD_CATSO_DIALOG };
    PicControl PicS;
    SoundList SoundControl;
    CSliderCtrl    m_ctlSteller_Gas;
    CSliderCtrl    m_ctlSteller_Dreh;
    CSliderCtrl    m_ctlSteller_Master;
    CString m_strWert_Gas;
    CString m_strWert_Dreh;
    CString m_strWert_Master;
    //}}AFX_DATA

    SoundDat SoundL;

    void UpdatePos(int TabChk);
    // Vom Klassenassistenten generierte Überladungen virtueller Funktionen
    //{{AFX_VIRTUAL(CCaTSoDlg)
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV-Unterstützung
    //}}AFX_VIRTUAL

// Implementierung
protected:
    HICON m_hIcon;                // Standart Bild

    // Generierte Message-Map-Funktionen
    //{{AFX_MSG(CCaTSoDlg)
    virtual BOOL OnInitDialog();
    afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    afx_msg void OnExit();
    afx_msg void OnJ_Options();
    afx_msg void OnC_Options();
    afx_msg void OnFilter();
    afx_msg void OnSignal();
    afx_msg void OnTimer(UINT nIDEvent);
    afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
    afx_msg void OnDoubleFilter();
    afx_msg void OnDoubleSignal();
    afx_msg void OnCustomdraw_Gas(NMHDR* pNMHDR, LRESULT* pResult);
    afx_msg void OnCustomdraw_Dreh(NMHDR* pNMHDR, LRESULT* pResult);
    afx_msg void OnCustomdraw_Master(NMHDR* pNMHDR, LRESULT* pResult);
    afx_msg void OnBConnect();
    afx_msg void OnBClose();
    afx_msg void OnStart();
    afx_msg void OnAbout();
    afx_msg void OnSound_Pfad();
    afx_msg void OnProj_Pfad();
    afx_msg void OnProj_Neu();
    afx_msg void OnProj_Laden();
    afx_msg void OnProj_Leer();
    afx_msg void Sel_Komp(UINT Index);
    afx_msg void Sel_Fahr(UINT Index);
    afx_msg void OnSetfocusShowKomp0();
    afx_msg void OnSetfocusShowKomp1();
    afx_msg void OnSetfocusShowKomp2();
    afx_msg void OnSetfocusShowKomp3();
    afx_msg void OnSetfocusShowKomp4();
    afx_msg void OnSetfocusShowKomp5();
    afx_msg void OnSetfocusShowKomp6();
    afx_msg void OnSetfocusShowKomp7();
    afx_msg void OnSetfocusShowKomp8();
    afx_msg void OnSetfocusShowKomp9();
    afx_msg void OnSetfocusShowFahr0();
    afx_msg void OnSetfocusShowFahr1();
    afx_msg void OnSetfocusShowFahr2();
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
        
private:
    void CalcDrehz();
    Old GasDreh;
    int MoveFiles(CString slSourceDir, CString slTargetDir);
    void CalcText(bool, int);    // Aufruf Klasse Soundsel und anzeigen des Ereignisses
    void OnHoch();
    void OnRunt();
};



Im Konstruktor setz ich z.B die Pfadnamen

C++:
CCaTSoDlg::CCaTSoDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CCaTSoDlg::IDD, pParent)
{
    //{{AFX_DATA_INIT(CCaTSoDlg)
    SoundControl.m_iKomp_Index = 0;
    SoundControl.m_iFahr_Index = 0;
    //}}AFX_DATA_INIT
    // Beachten Sie, dass LoadIcon unter Win32 keinen nachfolgenden DestroyIcon-Aufruf benötigt
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

    m_fdGangKonst[0] =  0;
    m_fdGangKonst[1] =  GANG1;
    m_fdGangKonst[2] =  GANG2;
    m_fdGangKonst[3] =  GANG3;
    m_fdGangKonst[4] =  GANG4;
    m_fdGangKonst[5] =  GANG5;
    m_fdGangKonst[6] =  GANG6;

    m_iGang = 0;
    Zeit = 0;
    GasDreh.Drehzahl_Alt = 0;
    m_iWert_Gas = 0;

    m_bKompAus = FALSE;

    running = FALSE;

    Bmp.m_bmpBack.LoadBitmap( IDB_BACK );

    PfadN.SoundPfad = "E:\\Sounds\\Car\\";
    PfadN.ProjektPfad = "E:\\Projekte\\";

    SockKom.SeDa            = &SndPuff;
    SockKom.FiSi            = &FiSi;
    SockKom.SoundOptions    = &SoundL;
    SockKom.m_strSound_Pfad    = &PfadN.SoundPfad;

    for (int a=0 ; a<ANZ_KOMP_LISTE ; a++)
    {
        SoundL.m_iKomp_Back_ID[a]    = 0;
        SoundL.m_iKomp_Spec_ID[a]    = 0;
        einmal[a] = FALSE;
    }
    for ( a=0 ; a<ANZ_FAHR_LISTE ; a++)
    {
        SoundL.m_iFahr_Engine_ID[a]    = 0;
        SoundL.m_iFahr_Road_ID[a]    = 0;
        SoundL.m_iFahr_Wind_ID[a]    = 0;
    }

    FiSi.Filter_AktivAll = FALSE;
    FiSi.Signal_AktivAll = FALSE;

    char buffer[_MAX_PATH];
     ::GetModuleFileName(::AfxGetInstanceHandle(),buffer,_MAX_PATH);
     CString Path=buffer;
     PfadN.HauptPfadname = (CString(buffer).Left(CString(buffer).ReverseFind('\\')+1));
}



Die Pfadnamen sind nun gesetzt der Hauptpfadname ist gleich dem Pfad in dem die Anwendung läuft.

Mit dem Debugger hab ich den String mal verfolgt und er wird einfach bei einem Timerereignis welches garnichts mit diesem String zu tun hat mitten im Programm gelöscht.
Normalerweise sollte der String bis zum ende des Programms in dieser Klasse unter der Membervariable "PfadN.Hauptpfadname" enthalten sein.

Vorher hat auch alles fehlerfrei funktioniert bis ich mein Programm mit einigen Variablen und Funktionen erweitert habe.

Durch erweiterungen des Programms kommen plötzlich noch andere seltsame fehler zum vorschein , wie das der Destruktor der Klasse auf einmal gar nicht mehr aufgerufen wird oder einige Dialogfelder beim aufruf einen Assertionfehler zurückgeben.

Das einzige was ich mir noch vorstellen könnte ist das ich dieses Programm auf mehreren Computern bearbeitet habe und VC++ damit nicht klar kommt.
dazu habe ich immer das ganze Projekt gezipt auf einen anderen Rechner kopiert und neu erstellt. Des öfteren auch neu angelegt.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
21.07.2004, 12:03 Uhr
~Sven
Gast


Kann es sein das du dir etwas mehr an Speicher dynamisch besorgst und diesen nicht wieder freigibst! Das hört sich nach deinen Angaben sehr danach an,das dein Programm probleme damit hat dir "freien" ram zu besorgen!

Achte auf jedenfall darauf das wenn du dir Speicher besorgst diesen wenn du ihn nicht mehr brauchst auch wieder freigibst! Den sonst liegen die Leichen überall herum!

sven
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
21.07.2004, 12:13 Uhr
~Groovejuice
Gast


Juhuu,
ich habe mein Programm wieder zum laufen gekriegt.

Ich hatte vorher alle Datenstrukturen in einer einzigen Headerdatei definiert und diese von allen Klassen includiert.
Nun hab ich erstmal die Datenstrukturen rausgenommen die nur von einzelnen Klassen benötigt werden und diese vor die entsprechende Klassendefinition gesetzt.
Das spart wohl einiges an Arbeitsspeicher.
Die Pfadnamen bleiben erhalten und die Dialogfelder geben keine Fehlermeldungen zurück.

Mein Programm läuft wieder einwandfrei auch wenn mir immer noch nicht klar ist wie man solche Fehler frühzeitig erkennt.

Die grösse meiner Anwendung liegt derzeit bei 5MB was denk ich mal ein ziemlich kleines Programm für heutige verhältnisse ist.

Mfg
Groove
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
21.07.2004, 12:43 Uhr
virtual
Sexiest Bit alive
(Operator)



Zitat von ~Groovejuice:
Juhuu,
Mein Programm läuft wieder einwandfrei auch wenn mir immer noch nicht klar ist wie man solche Fehler frühzeitig erkennt.


Die antwort ist ganz einfach und hat Tommix bereits gegeben: durch sauberes Programmieren!

WEnn einer Anwendung kein Speicher zur Verfügung steht, dann wird beim VC zB ein NULL Pointer zurückgeliefert.
Schnell ist mal sowas geschrieben worden, wo mit new oder malloc/realloc was belegt wird und nicht geprüft wird, ob denn auch alles okay ging. Die symptome deines Problems deuten für mich auf uninitialisierte Pointer, also zB:

C++:
void copy_or_not(const void*s , void* d, size_t l)
{
     static char x[1000];
     char* p;
     if (d) p = d;
    memcpy(p, s, l);
}


p ist in manchen Fällen unitialisiert, möglicherweise war die Intention mal gewesen sowas zu schreiben:

C++:
void copy_or_not(const void*s , void* d, size_t l)
{
     static char x[1000];
     char* p;
     if (d) p = d; else p = x; // Beachte das else!
    memcpy(p, s, l);
}


Aber wen man es erstmal vergessen hat, ist der Fehler im Zweifel da, eben erst sichtbar, wenn man das erste Mal die Funktion mit NULL für d aufruft.

Um auf die Sichere Seite zu gelangen:
1. asserts einfügen, wo immer geht. Denn dies sind macros, die man nach ausreichenden Tests in der Releaseversion des Programms auch einfach deaktivieren kann.
2. Lokale Variablen stets initialisieren
3. Funktionsrückgaben immer auf Fehler prüfen.
4. Doku immer genau lesen.
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ VC++ / MFC ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: