Benedikt: C++, SDL, OpenGL: Problem mit SDL_Quit()

Hallo,

ich hoffe das sich in diesem Forum min. 1 jemand befindet der sich mit meinem Problem auskennt. (Das ist ja wieder mal ein Deutsch. Aber ich glaube ihr wisst was ich meine.)

Nun gut.

Ich arbeite zurzeit an einem Projekt das sehr gross werden wird.
Das Problem das ich habe schleppe ich schon seit geraumer Zeit mit dem Projekt mit, aber bis jetzt habe ich das Problem immer verdrängt und desen Lösung auf später verschoben.
Habe auch mit Google immer wieder Suchen bezüglich meines Problems durchgeführt. Aber nicht einmal ansatzweise eine ähnliches Problem gefunden, geschweige den desssen Lösung.
Nun will ich das Problem aber endlich aus der Welt schaffen. Wie gesagt mein Projekt ist schon etwas sehr weit fortgeschritten und das heist das es auch ziemlich viel SourceCode gibt.
Die ausführbare kompilierte Datei ist gut 1 MB gross, So kann ich niemals alles hier posten.

Ein paar Informationen zu meinem System:
kernel-2.6.25-14.fc9.x86_64
gnome-session-2.22.3-1.fc9.x86_64
SDL_image-devel-1.2.6-6.fc9.x86_64
SDL_ttf-debuginfo-2.0.9-4.fc9.x86_64
SDL_gfx-2.0.16-5.fc9.x86_64
SDL-devel-1.2.13-3.fc9.x86_64
SDL-1.2.13-3.fc9.x86_64
SDL_gfx-devel-2.0.16-5.fc9.x86_64
SDL-static-1.2.13-3.fc9.x86_64
SDL_ttf-2.0.9-4.fc9.x86_64
SDL_ttf-devel-2.0.9-4.fc9.x86_64
SDL-debuginfo-1.2.13-3.fc9.x86_64
SDL_image-1.2.6-6.fc9.x86_64
SDL_gfx-debuginfo-2.0.16-5.fc9.x86_64
gcc-4.3.0-8.x86_64
libX11-1.1.4-1.fc9.x86_64

2 GB RAM
Intel Celeron D 3,2 GHz
nVidia GeForce 8500 GT, 512 MB
Aktuellste Treiber für Grafikkarte installiert.

Aber ich kann ja mal grob die wichtigsten Code teile für mein Problem zusammen fassen.

Also zuerst initialisiere ich SDL und dann OpenGL ich verwende auch die SDL_ttf, also lade ein paar Fonts.
Damit rendere ich beliebigen Text auf ein SDL_Surface und tu dann diese mit OpenGL auf den Screen rendern. Funktioniert einwandfrei. Nicht unbedingt das schnellste aber es reicht.

  
// Ein teil der init() Funktion  
{  
  writeLog("init()", LOG_INFO);  
  const SDL_VideoInfo* Info = NULL;  
  if(SDL_Init(SDL_INIT_EVERYTHING) != 0) {  
   writeLog("Couldn't init SDL", LOG_ERROR);  
   return EXIT_FAILURE;  
  }  
  
  Info = SDL_GetVideoInfo();  
  if(Info != NULL) {  
   ScreenWidth = Info->current_w / 2;  
   ScreenHeight = Info->current_h / 2;  
   ScreenHalfWidth = ScreenWidth / 2;  
   ScreenHalfHeight = ScreenHeight / 2;  
   ScreenAspect = (float)((float)ScreenWidth / (float)ScreenHeight);  
  } else {  
   ScreenWidth = 800;  
   ScreenHeight = 600;  
   ScreenHalfWidth = 400;  
   ScreenHalfHeight = 300;  
   ScreenAspect = 8.0f / 6.0f;  
   writeLog("Couldn't get Video Infos from SDL", LOG_WARNING);  
  }  
  
  int videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE;  
  if(Info->hw_available) {  
   videoFlags |= SDL_HWSURFACE;  
  } else {  
   videoFlags |= SDL_SWSURFACE;  
  }  
  if(Info->blit_hw) {  
   videoFlags |= SDL_HWACCEL;  
  }  
  
  
  SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1);  
  
  Screen = SDL_SetVideoMode(ScreenWidth, ScreenHeight, Info->vfmt->BitsPerPixel, videoFlags);  
  if(Screen == NULL) {  
   writeLog("Couldn't init Video Mode", LOG_ERROR);  
   return EXIT_FAILURE;  
  }  
  
  SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, 0);  
  
  
  if(TTF_Init() == -1) {  
   writeLog("Couldn't init TTF", LOG_ERROR);  
   return EXIT_FAILURE;  
  }  
  
  if(!fileExists("data/verdana.ttf")) {  
   writeLog("\"data/verdana.ttf\" is missing.", LOG_ERROR);  
  }  
  
  if(!fileExists("data/comic.ttf")) {  
   writeLog("\"data/comic.ttf\" is missing.", LOG_ERROR);  
  }  
  font1_16 = TTF_OpenFont("data/verdana.ttf", 16); if(font1_16 == NULL) {   writeLog("Couldn't load TTF-File: \"data/verdana.ttf\"", LOG_WARNING);  return EXIT_FAILURE; }  
  font1_28 = TTF_OpenFont("data/verdana.ttf", 28); if(font1_28 == NULL) {   writeLog("Couldn't load TTF-File: \"data/verdana.ttf\"", LOG_WARNING);  return EXIT_FAILURE; }  
  font1_48 = TTF_OpenFont("data/verdana.ttf", 48); if(font1_48 == NULL) {   writeLog("Couldn't load TTF-File: \"data/verdana.ttf\"", LOG_WARNING);  return EXIT_FAILURE; }  
  font1_56 = TTF_OpenFont("data/verdana.ttf", 56); if(font1_56 == NULL) {   writeLog("Couldn't load TTF-File: \"data/verdana.ttf\"", LOG_WARNING);  return EXIT_FAILURE; }  
  font2_16 = TTF_OpenFont("data/comic.ttf", 16); if(font2_16 == NULL) {   writeLog("Couldn't load TTF-File: \"data/comic.ttf\"", LOG_WARNING);  return EXIT_FAILURE; }  
  font2_28 = TTF_OpenFont("data/comic.ttf", 28); if(font2_28 == NULL) {   writeLog("Couldn't load TTF-File: \"data/comic.ttf\"", LOG_WARNING);  return EXIT_FAILURE; }  
  font2_48 = TTF_OpenFont("data/comic.ttf", 48); if(font2_48 == NULL) {   writeLog("Couldn't load TTF-File: \"data/comic.ttf\"", LOG_WARNING);  return EXIT_FAILURE; }  
  font2_56 = TTF_OpenFont("data/comic.ttf", 56); if(font2_56 == NULL) {   writeLog("Couldn't load TTF-File: \"data/comic.ttf\"", LOG_WARNING);  return EXIT_FAILURE; }  
  
  SDL_ShowCursor(true);  
  SDL_EnableUNICODE(0);  
  
  glViewport(0, 0, ScreenWidth, ScreenHeight);  
  glMatrixMode(GL_PROJECTION);  
  glLoadIdentity();  
  glClearDepth(1.0f);  
  glEnable(GL_DEPTH_TEST);  
  glDepthFunc(GL_LEQUAL);  
  gluPerspective(45.0f, ScreenAspect, 0.1f, 100.0f);  
  glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);  
  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);  
  glShadeModel(GL_SMOOTH);  
  glDisable(GL_CULL_FACE);  
  
  atexit(TTF_Quit);  
  atexit(SDL_Quit);  
 }

Hier wird dann jede menge Zeugs gerendert und berechnet.

Dann am Ende gebe ich die Fonts frei mit TTF_CloseFont() und die ScreenSurface mit SDL_FreeSurface() dann rufe ich TTF_Quit() auf und
 schließlich SDL_Quit() gleich nach SDL_Quit() kommt der aufruf exit(EXIT_SUCCESS). j

~~~c++

{ // Der letzte Teil der exit() Funktion
  writeLog("exit()", LOG_INFO);
  writeLog("Close Fonts", LOG_INFO);
  if(font1_16 != NULL) {  TTF_CloseFont(font1_16); }
  if(font1_28 != NULL) {  TTF_CloseFont(font1_28); }
  if(font1_48 != NULL) {  TTF_CloseFont(font1_48); }
  if(font1_56 != NULL) {  TTF_CloseFont(font1_56); }
  if(font2_16 != NULL) {  TTF_CloseFont(font2_16); }
  if(font2_28 != NULL) {  TTF_CloseFont(font2_28); }
  if(font2_48 != NULL) {  TTF_CloseFont(font2_48); }
  if(font2_56 != NULL) {  TTF_CloseFont(font2_56); }

writeLog("Free Screen Surface", LOG_INFO);
  if(Screen != NULL) {  SDL_FreeSurface(Screen); }

writeLog("Call TTF_Quit()", LOG_INFO);
  TTF_Quit();
  writeLog("Call SDL_Quit()", LOG_INFO); // Letzte Ausgabe in Logfile, danach absturz von Programm und XServer
  SDL_Quit();
  writeLog("Call exit()", LOG_INFO);
  exit(EXIT_SUCCESS);
 }

  
So und da mein Projekt auch sehr umfangreich ist habe ich auch ein Logfile wo das wichtigste mitgeloggt wird.  
  
Wenn ich nun mein Programm starte tut es das was ich mir davon erwarte. Alles einwandfrei. Wenn ich nun die [ESC] taste betätige oder das Fenster mit der Maus schließe wird intern der exit() pfad eingeschlagen.  
 Das heisst das Rendern des nächsten Frames wird nicht ausgeführt stattdessen wird mein Programm zum beenden vorbereitet. Das heisst sämtliche Resourcen werden freigegeben und dann meine Fonts,  
 ScreenSurface und TTF\_Quit() SDL\_Quit() wird aufgerufen.  
  
Wenn ich das mache ist der letzte Eintrag in mein Logfile vor dem SDL\_Quit() danach kommt nix mehr. Noch dazu wird mein XServer gleich mit beendet.  
  
Daraus schließe ich das SDL\_Quit() mein Programm zerschiesst und meinen XServer gleich mit. Aber ich finde nirgends einen Hinweis warum.  
  
Vom XServer erhalte ich nach dem Absturz folgende Meldung:  
  
  
  
Backtrace:  
0: /usr/bin/X(xf86SigHandler+0x65) [0x479ca5]  
1: /lib64/libc.so.6 [0x30410322a0]  
2: /usr/lib64/xorg/modules/extensions//libglx.so(\_\_glXDeassociateContext+0x35) [0x7f7d46bf3265]  
3: /usr/lib64/xorg/modules/extensions//libglx.so(\_\_glXContextDestroy+0xf) [0x7f7d46bef63f]  
4: /usr/lib64/xorg/modules/extensions//libglx.so [0x7f7d46bf24f1]  
5: /usr/lib64/xorg/modules/extensions//libglx.so(\_\_glXFreeContext+0x6c) [0x7f7d46bf17cc]  
6: /usr/lib64/xorg/modules/extensions//libglx.so [0x7f7d46bf1813]  
7: /usr/bin/X(FreeResourceByType+0x105) [0x42ea45]  
8: /usr/lib64/xorg/modules/extensions//libglx.so [0x7f7d46bee12e]  
9: /usr/lib64/xorg/modules/extensions//libglx.so [0x7f7d46bf1ae2]  
10: /usr/bin/X(Dispatch+0x364) [0x4467f4]  
  
11: /usr/bin/X(main+0x45d) [0x42cc4d]  
12: /lib64/libc.so.6(\_\_libc\_start\_main+0xfa) [0x304101e32a]  
13: /usr/bin/X(FontFileCompleteXLFD+0x281) [0x42c029]  
  
Fatal server error:  
Caught signal 11.  Server aborting  
  
  
  
Vielleicht hilft das was.  
Wie gesagt sonst finde ich in keinem Logfile irgendeinen Hinweis.  
In der SDL\_Quit() muss irgendetwas vor sich gehen was diesen Bug verursacht. Kann ich da die SDL falsch verwendet haben, sodass die Aufräumroutine von SDL um sich schiesst?  
Aber ich kann doch nicht einfach den SDL\_Quit() aufruf komplett weglassen.  
  
Ich habe mein Projekt auch noch auf keinem anderen System getestet z. B. Windows oder sowas. Der Hauptgrund dafür ist das ich kein Microsoft-Produkt besitze, auch kein Windows. Ich kann auch auf keinem mir zugänglichen Windows-PC ausführlichere Tests durchführen, das ist ein Ding der unmöglichkeit. Zudem ist mein Programm auf Linux optimiert/spezialisiert geschrieben.  
  
Also das wäre echt toll wenn es hier jemand gibt der mir Helfen kann.  
Vielen Dank erstmal wenn ihr euch zumindest mein Problem bis hierher durchgelesen habt.  
  
  
Grüße  
  
Benedikt
  1. Hallo!

    1. Hast Du schon mal einen Debugger bemüht und einen Breakpoint auf das SDL_Quit gesetzt?

    atexit(irgendwas);  
      
    /*und  
      
    später */  
      
    irgendwas();  
    
    

    riecht nach nach einem free() auf einen nicht genullten Zeiger auf dem schon mal free() aufgerufen wurde.

    1. Wieviele Threads hat das Programm?

    2. Solche "Spaghetti"

      
     font1_16 = TTF_OpenFont("data/verdana.ttf", 16); if(font1_16 == NULL) {   writeLog("Couldn't load TTF-File: \"data/verdana.ttf\"", LOG_WARNING);  return EXIT_FAILURE; }  
    /* [...] */  
      font2_56 = TTF_OpenFont("data/comic.ttf", 56); if(font2_56 == NULL) {   writeLog("Couldn't load TTF-File: \"data/comic.ttf\"", LOG_WARNING);  return EXIT_FAILURE; }
    

    machen den code nicht gerade wartungsfreundlich; es gibt Arrays, Schleifen etc. und falls Du C++ verwendest auch noch vector, map, iterator....

    Grüsse

    Solkar

      1. Hast Du schon mal einen Debugger bemüht und einen Breakpoint auf das SDL_Quit gesetzt?#

      Ja, habe ich. Aber davon werde ich ned schlauer, absolut ned.

      Klingt jetzt blöd. Aber das passiert jetzt nicht jedesmal. Es kann jetzt auch sein das sich das Programm so beendet wie es soll und der XServer bleibt ganz. Also mit dem Debugger bin ich bis jetzt noch nich weitergekommen. Debugger brachte noch keine Ergebnis.

      riecht nach nach einem free() auf einen nicht genullten Zeiger auf dem schon mal free() aufgerufen wurde.

      1. Wieviele Threads hat das Programm?

      Ich habe die anderen Threads auch schon alle abgeschalten. Also nur mit einem laufen lassen. Das ändert gar nix. Also 1 Thread hat das Programm.

      1. Solche "Spaghetti"

      font1_16 = TTF_OpenFont("data/verdana.ttf", 16); if(font1_16 == NULL) {   writeLog("Couldn't load TTF-File: "data/verdana.ttf"", LOG_WARNING);  return EXIT_FAILURE; }
      /* [...] */
        font2_56 = TTF_OpenFont("data/comic.ttf", 56); if(font2_56 == NULL) {   writeLog("Couldn't load TTF-File: "data/comic.ttf"", LOG_WARNING);  return EXIT_FAILURE; }

      
      >   
      > machen den code nicht gerade wartungsfreundlich; es gibt Arrays, Schleifen etc. und falls Du C++ verwendest auch noch vector, map, iterator....  
        
      Das ist zwar lieb gemeint, aber bringt mir nicht wirklich was.  
        
      Benedikt
      
        1. Hast Du schon mal einen Debugger bemüht und einen Breakpoint auf das SDL_Quit gesetzt?#

        Ja, habe ich. Aber davon werde ich ned schlauer, absolut ned.

        Wenn Du nicht IN den Aufruf "stepst" sondern ihn in einem "Step" ausführst nicht...

        Gegen Debug-Versionen linken und IN den Aufruf "steppen"!

        Klingt jetzt blöd. Aber das passiert jetzt nicht jedesmal. Es kann jetzt auch sein das sich das Programm so beendet wie es soll und der XServer bleibt ganz. Also mit dem Debugger bin ich bis jetzt noch nich weitergekommen. Debugger brachte noch keine Ergebnis.

        Das klingt schon zweimal nach einem Deallocationsproblem.

        Also: Debuggen!

        1. Wieviele Threads hat das Programm?

        Ich habe die anderen Threads auch schon alle abgeschalten. Also nur mit einem laufen lassen. Das ändert gar nix. Also 1 Thread hat das Programm.

        Glaub ich noch nicht.

        Dass Du selbst keine eigenen Threads erzeugst ist kein hinreichendes Kriterium; wie hast Du z.B. ermittelt, dass die Bibliotheken keine eigenen Threads erzeugen; etwa für die Oberfläche?

        1. Solche "Spaghetti"
          [...]
          machen den code nicht gerade wartungsfreundlich; es gibt Arrays, Schleifen etc. und falls Du C++ verwendest auch noch vector, map, iterator....

        Das ist zwar lieb gemeint,

        Das ist weder lieb noch böse gemeint, sondern ist ein Hinweis zur Verbesserung Deines Programmierstils.

        aber bringt mir nicht wirklich was.

        Die Logik dieser Aussage solltest Du einmal selbst hinterfragen.

        Grüsse

        Solkar

        1. Gegen Debug-Versionen linken und IN den Aufruf "steppen"!

          Ich habe den SDL_Quit bis zum letzten Aufruf Zeile für Zeile zerlegt. Nichts. Das Programm beendete sich bei jedem Debug versuch einwandfrei.
           Da finde ich nichts was mir bei der Lösung hilft.
           Und wenn ich was finde, das ist alles SDL intern, da müsste ich ja in der SDL den Fehler ausmerzen. Aber das will ich nicht.
          Ich gehe stupide davon aus das alle Fremd-Libs absolut Fehlerfrei sind. Der Fehler befindet sich immer beim User also bei mir im Programm.

          Der läuft die SDL_Quit sogar zweimal durch und die TTF_Quit auch.
          zum einen weil es in meiner exit() Funktion drinsteht zum andern weil es bei atexit() eingetragen ist. Und wenn er beim ersten Durchlauf keinen Fehler macht aber beim 2. Durchlauf dann muss das SDL intern sein.
          Und das schließe ich durch meine Annahme aus. SDL* = Bugfrei.
          Und selbst wenn kann ich mir nicht vorstellen das grad ich einen Bug bei der SDL finde. Der Bug muss in meinem Code sein aber wo?
          Ich habe jetzt sogar nur mal die Init Funktion und die Exit Funktion in eine eigenes Programm gepackt. Also keinen Code außenrum, außer die Log-Funktionalität. Das Problem tritt genauso wieder auf.
          Es wird auch nichts gerendert, aber die Events werden verarbeitet.
          Wie davor auch kann es sein das sich das Programm 4 mal hintereinander einwandfrei beendet und beim 5. mal alles zerschiesst.

          Klingt jetzt blöd. Aber das passiert jetzt nicht jedesmal. Es kann jetzt auch sein das sich das Programm so beendet wie es soll und der XServer bleibt ganz. Also mit dem Debugger bin ich bis jetzt noch nich weitergekommen. Debugger brachte noch keine Ergebnis.

          Das klingt schon zweimal nach einem Deallocationsproblem.

          Also: Debuggen!

          Wie gesagt ich finde leider nichts in der Richtung.

          1. Wieviele Threads hat das Programm?

          Ich habe die anderen Threads auch schon alle abgeschalten. Also nur mit einem laufen lassen. Das ändert gar nix. Also 1 Thread hat das Programm.

          Glaub ich noch nicht.

          Dass Du selbst keine eigenen Threads erzeugst ist kein hinreichendes Kriterium; wie hast Du z.B. ermittelt, dass die Bibliotheken keine eigenen Threads erzeugen; etwa für die Oberfläche?

          Das kann ich mir sehr schwer vorstellen.

          1. Solche "Spaghetti"
            [...]
            machen den code nicht gerade wartungsfreundlich; es gibt Arrays, Schleifen etc. und falls Du C++ verwendest auch noch vector, map, iterator....

          Das ist zwar lieb gemeint,

          Das ist weder lieb noch böse gemeint, sondern ist ein Hinweis zur Verbesserung Deines Programmierstils.

          aber bringt mir nicht wirklich was.

          Die Logik dieser Aussage solltest Du einmal selbst hinterfragen.

          Willst du jetzt wegen solcher Lapalien mit mir einen Streit anzetteln?
          Das was du hier kritisierst ist eher ein Stilbruch, aber dieses Stück Code tut seinen Dienst. Man kann das ja dann immer noch wegoptimieren mit Arrays und Schleifen wie du schon so schön sagtest.
          Aber dennoch bringt es mir nichts wenn du sagst das ich das anders schöner schreiben kann.
          Die Funktion dieses Stück Codes wäre immer noch die gleiche.
          Es würden immer noch 8 mal ein Font geöffnet mit verschiedenen Größen und irgendwo gespeichert.
          Ob das nun in einem Array ist oder in 8 verschiedenen selbstständigen Variablen ist doch für mein Problem völlig Egal.

          Ich habe da auch noch eine schwache Verteidigung. Es gibt viele Beispiele im Internet (verschiedene Tutorials, teilweise findet man auch mit Google labs) oder verschiedene Bücher.
          Dort finden sich oft solche Beispiele.
          Es ist halt auch immer eine Geschmacksfrage.
          Der eine findet 8 Variablen besser und der andere ein Array mit 8 Elementen. Aber im Endeffekt bewirken beide dasselbe. Die Daten sage ich jetzt mal sind nur anders organisiert.

          Aber ich wäre dir sehr verbunden wenn wir unser Augenmerk auf mein tatsächliches Problem richten könnten.

          Benedikt

          1. Willst du jetzt wegen solcher Lapalien mit mir einen Streit anzetteln?

            Hoppla! Du stehst bei der Fehlersuche gerade selbst erheblich im Wege.

            Für sowas ist mir meine Zeit zu schade.

            Grüsse

            Solkar

            1. Ich wollte nur deinen punkt 4) aus deinem ersten Posting aus diesen Thread streichen und ignorieren.

              Benedikt

              1. Können wir nicht einfach alles zum Thema punkt 4) bei dem belassen.
                Jeder denkt sich seinen Teil und wir blenden alles dem bezüglich bis zur Problemlösung aus?
                Differenzen wird es immer geben. Aber es muss doch möglich sein sowas kurz zu vergessen und sich auf das wesentliche zu konzentrieren.
                Ich gebe dir ja recht. Der Code ist so nicht schön.
                Der ganze Code ist an mehreren stellen nicht schön. Aber man wird auch in schon als perfekt abgehakten Code noch was zu bemängeln finden.

                Also ich wäre dafür das man trotz diesem Punkt 4) und allem was danach bezüglich Punkt 4) gefolgt ist, sich auf mein wirkliches Problem beschränkt.

                Sollte ich die falsche Wortwahl getroffen haben, möchte ich mich dafür entschuldigen.

                Benedikt

                1. Können wir nicht einfach alles zum Thema punkt 4) bei dem belassen.

                  Nein.

                  Jeder denkt sich seinen Teil und wir blenden alles dem bezüglich bis zur Problemlösung aus?

                  Du möchtest offenbar gerne, dass Dein Code Anklang findet.

                  Sorry, aber dazu ist der Code aber einfach nicht gut genug:

                  Fest "eingebrannte" globale Pfade in den Tiefen irgendeiner Funktion sind eben kein guter Stil; genauso wenig wie "ausgerollte" Schleifen.

                  Wenn Du solchen Code vorlegst kannst Du nicht erwarten, dass andere Programmierer mit Dir auf Augenhöhe technisch diskutieren.

                  Differenzen wird es immer geben. Aber es muss doch möglich sein sowas kurz zu vergessen und sich auf das wesentliche zu konzentrieren.

                  Nicht Differenzen sind Dein Problem sondern Deine Einstellung.

                  In Deinem Code sind keine Mechanismen zur Vermeidung von häufigen Speicherlecks und Bereichsüberschreitungen zu finden; std::vector<T>, std::map<T> und dergleichen sind aber genau dafür gedacht.

                  Wenn Du an Stellen die nach Containern "schreien" solche nicht verwendest setzt Du sie auch nicht in kritischen Codeteilen ein; erzähl mir bitte nicht, der Rest Deines Codes sähe besser aus.

                  Es erfordert zugegebenermassen einigen Aufwand, sich in die STL einzuarbeiten.

                  Aber zumindest ein (C) Array mit const char* und einem (const char*) NULL als Terminator sollte drin sein.

                  Ich gebe dir ja recht. Der Code ist so nicht schön.
                  Der ganze Code ist an mehreren stellen nicht schön. Aber man wird auch in schon als perfekt abgehakten Code noch was zu bemängeln finden.

                  Wenn der Code nicht funktioniert?
                  Auf jeden Fall!

                  Also ich wäre dafür das man trotz diesem Punkt 4) und allem was danach bezüglich Punkt 4) gefolgt ist, sich auf mein wirkliches Problem beschränkt.

                  Deine Probleme sind folgende:

                  • Du scheust Dich offenbar davor mit dem Debugger systematisch zu arbeiten:

                  Und wenn ich was finde, das ist alles SDL intern, da müsste ich ja in der SDL den Fehler ausmerzen. Aber das will ich nicht.

                  Damit stehst Du nicht allein; viele Programmierer, die von Skript-Sprachen zu C/C++ gekommen sind, zeigen dies Verhalten; meist sind fehlende Grundkenntnisse in Assembler das Hauptproblem.

                  Aber C und C++ sind keine Skript-Sprachen.

                  Es nützt aber nichts jahrelang die Sinnlosigkeit von Debug-Sitzungen zu betonen statt sich einmal zu erarbeiten was EAX, ESP... denn wohl bedeuten.

                  • Du verwirfst Lösungsansätze ohne sie auszuprobieren:

                  Dass Du selbst keine eigenen Threads erzeugst ist kein hinreichendes Kriterium; wie hast Du z.B. ermittelt, dass die Bibliotheken keine eigenen Threads erzeugen; etwa für die Oberfläche?

                  Das kann ich mir sehr schwer vorstellen.

                  Es ist unerheblich ob wir uns etwas vorstellen können. Test und Analyse  schaffen Gewissheit.

                  Auf diese Hypothese

                  atexit(irgendwas);

                  /*und

                  später */

                  irgendwas();

                  riecht nach nach einem free() auf einen nicht genullten Zeiger auf dem »» »» schon mal free() aufgerufen wurde.

                  bist Du bislang auch nicht eingegangen.

                  Warum eigentlich nicht?
                  Was spricht gegen ein "//" vor dem atexit() und ein paar Testläufe?

                  Sollte ich die falsche Wortwahl getroffen haben, möchte ich mich dafür entschuldigen.

                  Die Entschuldigung ist angenommen, aber das heißt noch nicht, dass wir weitermachen.

                  Wenn Du bei jeder Kritik an Deinem Code derart defensiv reagierst kommen wir nicht weiter.

                  ---

                  Solche Debatten sind im Bereich C/C++ nicht selten; die kenne ich seit meinem ersten Projekt (und das ist schon etwas länger her):

                  "Nein, Debuggen brächte nichts!"
                  "Die STL brächte nichts, die kostet nur Performance und ist buggy!"
                  "Mein Code funktioniert zwar grad nicht, ist aber ansonsten SUPER!"
                  [...]

                  So wurde aber noch nie ein Problem gelöst, mittels "Code aufräumen" und Debuggen hingegen schon!

                  Einen Hoffnungsschimmer sehe ich aber bei Dir:

                  Ich gehe stupide davon aus das alle Fremd-Libs absolut Fehlerfrei sind. Der Fehler befindet sich immer beim User also bei mir im Programm.

                  Das ist generell eine gute Einstellung!

                  Allerdings ist es in diesem konkreten Fall durchaus möglich, dass in OpenSource-Bibliotheken, die irgendwann mal von 32 auf 64 Bit migriert wurden irgendwo noch ein Fehler steckt und sei es nur im Zusammenwirken mit X, dem konkreten Treiber und Kernel usw.

                  ---

                  Jetzt müsstest Du Dir mal überlegen, wie Du mit dem Problem weiter umgehen willst.

                  Grüsse

                  Solkar

                  Benedikt

                  1. »»

                    Also zunächst einmal möchte ich ein paar Dinge korregieren. Das kann ich nicht so hinnehmen.

                    Du möchtest offenbar gerne, dass Dein Code Anklang findet.

                    Diese Aussage ignoriere ich mal.

                    Sorry, aber dazu ist der Code aber einfach nicht gut genug:

                    Das ist akzeptiert, darauf möchte ich aber später zurückkommen.

                    Fest "eingebrannte" globale Pfade in den Tiefen irgendeiner Funktion sind eben kein guter Stil; genauso wenig wie "ausgerollte" Schleifen.

                    Auch dazu später mehr.

                    Wenn Du solchen Code vorlegst kannst Du nicht erwarten, dass andere Programmierer mit Dir auf Augenhöhe technisch diskutieren.

                    OK. Das kann ich halbwegs verstehen auch wenn ich da auf den Sinn eines Forums oder eben gerade dieses Forums verweisen könnte.

                    Ich bin momentan 16 Jahre alt. Lerne Elektroniker für Geräte und System, wollte aber ursprünglich Fachinformatiker für
                    Anwendungsentwicklung lernen. Aber ein anders Angebot war eben besser und ich bereue es auch keineswegs.
                    Später möchte ich dann Informatik und Elektrotechnik studieren. Ja, beide.

                    Im Jahre 2003 habe ich mir ein Buch über C++ und die Spieleprogrammierung von einem bekannten Verlag gekauft.
                    Damit fing ich an mich für C/C++ und Programmierung allgemein zu interessieren und es schließlich auch zu lernen.
                    Skriptsprachen usw. kamen erst später ((X)HTML, CSS, JavaScript, Java, PHP und MySQL, auch ein wenig Assembler)
                    Ich möchte keineswegs behaupten das ich da irgendwo ein Experte bin. Aber ich behaupte das ich von allen ein
                    wenig Ahnung habe.
                    Und Lernen ist nicht irgendwann Abgeschlossen, Lernen ist ein fortwährender, endloser Prozess.

                    Ich habe auch noch nie  mit einem professionellem Programmierer zusammengearbeitet oder geschweige den persönlich gesprochen.
                    OK, da gibt es jetzt 1 Ausnahme nämlich ein 4 tägiges Praktikum bei einer kleinen Firma. Aber da habe ich nicht so viel
                    gelernt das es jetzt der Rede wert wäre. Ich habe nur Bücher und das Internet womit ich mein Wissen ausbaue(-n kann).

                    Deine Probleme sind folgende:

                    • Du scheust Dich offenbar davor mit dem Debugger systematisch zu arbeiten:

                    Und wenn ich was finde, das ist alles SDL intern, da müsste ich ja in der SDL den Fehler ausmerzen. Aber das will ich nicht.

                    Damit meinte ich eher das ich mit der Entwicklung von SDL nichts zu tun habe, die SDL intern sehr komplex ist, mein stupide Annahme SDL = bugfrei.

                    Damit stehst Du nicht allein; viele Programmierer, die von Skript-Sprachen zu C/C++ gekommen sind, zeigen dies Verhalten; meist sind fehlende Grundkenntnisse in Assembler das Hauptproblem.

                    Aber C und C++ sind keine Skript-Sprachen.

                    Das habe ich schon richtig gestellt, ich habe vor C++ keine andere Sprache gelernt. Grundkenntnisse in Assembler sind sehr wohl vorhanden.

                    Es nützt aber nichts jahrelang die Sinnlosigkeit von Debug-Sitzungen zu betonen statt sich einmal zu erarbeiten was EAX, ESP... denn wohl bedeuten.

                    • Du verwirfst Lösungsansätze ohne sie auszuprobieren:

                    Dass Du selbst keine eigenen Threads erzeugst ist kein hinreichendes Kriterium; wie hast Du z.B. ermittelt, dass die Bibliotheken keine eigenen Threads erzeugen; etwa für die Oberfläche?

                    Das kann ich mir sehr schwer vorstellen.

                    Es ist unerheblich ob wir uns etwas vorstellen können. Test und Analyse  schaffen Gewissheit.

                    Ich kann sehr wohl lesen. GDB sagt es wird nur ein Thread erstellt und ich glaube das.
                    Außerdem kenne ich sehr wohl meinen Code. Und da wird nun mal kein 2. Thread erstellt.

                    Auf diese Hypothese

                    atexit(irgendwas);

                    /*und

                    später */

                    irgendwas();

                    riecht nach nach einem free() auf einen nicht genullten Zeiger auf dem »» »» schon mal free() aufgerufen wurde.

                    bist Du bislang auch nicht eingegangen.

                    Warum eigentlich nicht?
                    Was spricht gegen ein "//" vor dem atexit() und ein paar Testläufe?

                    Den Fehler vermutete ich in Zusammenhang mit meiner Funktion die den Text rendert.
                    Außerdem habe ich das sehr wohl auch getestet, auch mit debugger.
                    Die exit() Funktionen liefen immer fehlerfrei, egal wie oft sie aufgerufen wurden. Aber erst nachdem ich den Code ein wenig bearbeitet habe. (Dazu unten mehr)

                    Wie man obigen Text entnehmen kann habe ich nie irgendwelchen Informatikunterricht besucht.
                    Mir hat auch nie jemand gesagt wie ich schönen Code zu schreiben habe. Wie ich dies und jenes
                    Problem Codetechnisch zu lösen habe. Einige Dinge habe ich mit der Zeit verschiedenen Quellen
                    entnehmen können, aber ich war/bin darauf angwiesen solche Quellen erst einmal zu finden.
                    Aber ich bin auch ein Verfechter des Selbststudiums, man kann mit der richtigen Motivation
                    Sachen viel schneller und besser verstehen und lernen auch vorausgesetzt es gibt genug
                    Quellen mit Information. Aber die Motivation ist sehr ausschlaggebend.

                    Wenn ich z. B. den Code von irgendeinem OpenSource Projekt anschaue. z. b. gcc,kernel,httpd,o. ä.
                    So hat der Code viele Unterschiede im Vergleich zu meinem Code. Aber die OpenSource-projekte
                    wurden von Experten gecodet.
                    Solchen Code zu schreiben habe ich mir noch nicht beigebracht, ich habe bis jetzt auch nie
                    die Notwendigkeit gesehen meinen Code/Programmierstil irgendwie drastisch zu verändern.
                    Bis jetzt konnte ich jedes Problem lösen. Ob die Lösung nun einem Experten gefallen würde
                    oder nicht, darüber habe ich mir nie Gedanken gemacht. Für mich war wichtig, das Problem ist
                    gelöst und der Code funktioniert.
                    Aber wenn ich später ein Informatikstudium beginnen und abschließen möchte und danach einen
                    (Informatik-)Job habe. So denke ich mir doch das ich meinen Programmierstil/Code vll. doch ein wenig
                    ändern/verbessern sollte. Da mein Team ja dann auch aus Experten besteht.

                    Gibt es denn irgendein Buch oder eine Internetseite(Tutorial, Vorlesung, Diplomarbeit, eBook)
                    über das verfassen von schönem Code, Tabus, goldenen Regeln, Vorschriften, Verboten, Standards
                    z.B. das mit den

                    Fest "eingebrannte" globale Pfade in den Tiefen irgendeiner Funktion sind eben kein guter Stil; genauso wenig wie "ausgerollte" Schleifen.

                    Wie man solche Sachen schön und elegant löst.
                    Damit ich in Zukunft Code schreiben kann den auch Experten akzeptieren.

                    Abschließend möchte ich auf mein eigentliches Problem und Thema dieses Threads zurückkommen.

                    Wie gesagt verdächtigte ich schon länger diese Funktion:

                      
                     void renderText(const char* text, SDL_Color color, TTF_Font* font, SDL_Rect* location)  
                     {  
                      if(font == NULL || text == NULL || location == NULL) {  
                       writeLog("renderText(): Get a NULL Pointer.", LOG_ERROR);  
                       return;  
                      }  
                      
                      SDL_Surface* intermediary = NULL;  
                      SDL_Surface* initial = TTF_RenderUTF8_Blended(font, text, color); // Use SDL_TTF to render our text  
                      if(initial == NULL) {  
                       writeLog("renderText(): TTF_RenderUTF8_Blended() Get a NULL Pointer.", LOG_ERROR);  
                       return;  
                      }  
                      int texture = 0;  
                      int w = nextPowerOfTwo(initial->w); // Convert the rendered text to a known format  
                      int h = nextPowerOfTwo(initial->h);  
                      
                      intermediary = SDL_CreateRGBSurface(0, w, h, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);  
                      
                      if(intermediary == NULL) {  
                       writeLog("renderText(): SDL_CreateRGBSurface() Get a NULL Pointer.", LOG_ERROR);  
                       return;  
                      }  
                      
                      SDL_BlitSurface(initial, 0, intermediary, 0); // copy surface  
                      
                      glEnable2D();  
                      glDisable(GL_DEPTH_TEST);  
                      
                      glGenTextures(1, (GLuint*)&texture);// Tell GL about our new texture  
                      glBindTexture(GL_TEXTURE_2D, texture);  
                      glTexImage2D(GL_TEXTURE_2D, 0, 4, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, intermediary->pixels);  
                      
                      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);// GL_NEAREST looks horrible, if scaled...  
                      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  
                      
                      glEnable(GL_TEXTURE_2D);// prepare to render our texture  
                      glBindTexture(GL_TEXTURE_2D, texture);  
                      glColor3f(1.0f, 1.0f, 1.0f);  
                      
                      glBegin(GL_QUADS);  // Draw a quad at location  
                      glTexCoord2f(0.0f, 1.0f); // Recall that the origin is in the lower-left corner That is why the TexCoords specify different corners than the Vertex coors seem to.  
                      glVertex2f(location->x,     location->y);  
                      glTexCoord2f(1.0f, 1.0f);  
                      glVertex2f(location->x + w, location->y);  
                      glTexCoord2f(1.0f, 0.0f);  
                      glVertex2f(location->x + w, location->y + h);  
                      glTexCoord2f(0.0f, 0.0f);  
                      glVertex2f(location->x,     location->y + h);  
                      glEnd();  
                      glFinish(); // Bad things happen if we delete the texture before it finishes  
                      glEnable(GL_DEPTH_TEST);  
                      glDisable2D();  
                      
                      location->w = initial->w; // return the deltas in the unused w,h part of the rect  
                      location->h = initial->h;  
                      
                      // Clean up  
                      SDL_FreeSurface(initial);  
                      initial = (SDL_Surface*)NULL;  
                      SDL_FreeSurface(intermediary);  
                      intermediary = (SDL_Surface*)NULL;  
                      glDeleteTextures(1, (GLuint*)&texture);  
                      texture = 0;  
                     }
                    

                    Wie gesagt die Funktion habe ich mir ausgeliehen und abgeändert.
                    Hatte ich die Funktion im Render-Teil drin. So war die Wahrscheinlichkeit, das
                    mein Programm Amok läuft um 80% erhöht. Hatte ich den Render-Teil komplett
                    leer, so war die Wahrscheinlichkeit fast 0%.
                    Ob das Problem nun gelöst ist kann ich nicht sagen. Jegliche Debug-versuche
                    bringen nur das Ergebnis das ich ohne Debugger auch erreiche: Program exited normally.
                    Also ich betrachte das Problem bis auf weiteres für gelöst.

                    Nun möchte ich meine überarbeitet Version noch kurz posten um zu erfahren ob der Code nun beser ist oder ob es immer noch der gleiche Mist ist.

                      
                    #define FONT_MAX_SIZE (100)  
                    // 4 Globale Arrays:  
                    TTF_Font* FontVerdana[(FONT_MAX_SIZE + 1)] = {(TTF_Font*)NULL};  
                    TTF_Font* FontTahoma [(FONT_MAX_SIZE + 1)] = {(TTF_Font*)NULL};  
                    TTF_Font* FontCourier[(FONT_MAX_SIZE + 1)] = {(TTF_Font*)NULL};  
                    TTF_Font* FontComic  [(FONT_MAX_SIZE + 1)] = {(TTF_Font*)NULL};  
                      
                    // In der init() Funktion  
                    // Wäre da eine Funktion besser, die dann ein mal für jede Schrift aufgerufen wird?  
                    // Aber dann könnte man ja die 4 Funktionsaufrufe wieder in eine Schleife packen??  
                    // Aber die festen,globalen Pfade gibt es immer noch?  
                    // 4 mal das ganze; einmal für jedes Array  
                       for(unsigned short i = 0; i < FONT_MAX_SIZE; ++i) {  
                       FontVerdana[i] = TTF_OpenFont("data/verdana.ttf", i + 1);  
                       if(FontVerdana[i] == (TTF_Font*)NULL) {  
                        writeLog("Couldn't open Font \"verdana.ttf\"", LOG_ERROR);  
                        return EXIT_FAILURE;  
                       }  
                      }  
                      
                      
                      
                    // und exit() Funktion, 4 mal; für jedes Array 1 mal  
                      for(unsigned short i = 0; i < FONT_MAX_SIZE; ++i) {  
                       if(FontVerdana[i] != (TTF_Font*)NULL) {  
                        TTF_CloseFont(FontVerdana[i]);  
                        FontVerdana[i] = (TTF_Font*)NULL;  
                       }  
                      }  
                      
                      
                    
                    

                    Das einzige Anliegen das ich noch hätte, wären ein paar Quellen mit Rezepten für schöneren, besseren, schnelleren Code.
                    Natürlich nur wenn das möglich ist.

                    Benedikt