Ergebnis 1 bis 17 von 17

Thema: [C++] Spaß mit Enums ("Spaß" == "Problem")

  1. #1

    [C++] Spaß mit Enums ("Spaß" == "Problem")

    Ich habe ein kleines Problem. Ich habe Code, bei dem ich eine Kombination von Werten angeben muß. Soweit kein Problem, läßt sich mit Zweierpotenzen und Addition wunderbar erledigen.
    Damit das Ganze übersichtlicher aussieht habe ich mich entschlossen, enums zu verwenden.
    Ein paar Deklarationen aus meinem Code:
    Code:
    enum { S_None = 0, S_Barrel = 1, S_Top = 2, S_Under = 4, S_Grip = 8, S_Stock = 16 }; //Spaces
    int enmSpaces;
    Etwas weiter im Code setze ich dann einen Wert und gebe ihn aus:
    Code:
    enmSpaces = S_Barrel|S_Top|S_Grip;
    
    char * acharTempChar;
    acharTempChar = (char*) malloc(256);
    if(acharTempChar!=NULL)
    {
     sprintf(acharTempChar, "%i", enmSpaces);
     outG_Debug->value(acharTempChar);
    
     free(acharTempChar);
    }
    Ich sollte 1|2|8 = 11 zurückbekommen.
    Was ich zurückbekomme ist irgendein zehnstelliger Wert, der mit nichts irgendwas zu tun hat.
    Interessanterweise bekomme ich, wenn ich mehrere Variablen gleich definiere, unterschiedliche Werte zurück. Das riecht für mich stark nach uninitialisiertem Speicher, allerdings ändert sich nichts am Ergebnis, wenn ich enmSpaces malloc()e.

    Ich weiß mit 100%iger Sicherheit, daß es an dem Code ab char * nicht liegen kann. Das ist normaler Standardcode, wie ich ihn bei FLTK in bestimmten Situationen brauche und ich bekomme bei anderen Werten eine korrekte Ausgabe.

    Hat irgendwer eine Ahnung, warum meine Enums Amok laufen? Sollte ich den ganzen Ramsch einfach als einzelne const-Variablen definieren?

    Oh, noch was... Ich habe gerade gemerkt, daß der Fehler bei ALLEN enumerierten Werten auftritt, nicht nur bei denen, die ich mit | verbinde.

  2. #2
    Code:
    #include <stdio.h>
    
    enum { S_None = 0, S_Barrel = 1, S_Top = 2, S_Under = 4, S_Grip = 8, S_Stock = 16 }; //Spaces
    int enmSpaces;
    
    int main(void)
    {
      enmSpaces = S_Barrel|S_Top|S_Grip;
      printf("%i", enmSpaces);
    }
    Wenn ich dieses Codestück übersetze und ausführe kommt 11 raus. Deine Enums laufen also. Wenn du deine Zahl in einen String umwandeln möchtest (oder was hast du mit sprintf vor?), würde ich [FONT=courier new]itoa(char* dest, int src, int radix)[/FONT] verwenden. Oder versuch einfach, &acharTempChar als Parameter zu verwenden. Ansonsten, schreib welchen Compiler du verwendest und gib mir den Konsolenoutput, viell. kann ich da mehr rauslesen

  3. #3
    itoa() wäre eine Idee. Nicht per enum definierte Integerwerte werden übrigens mit dem derzeitigen Code korrekt angezeigt.

    Oh, und exit(enmSpaces); liefert den korrekten Wert.



    Der Compiler ist gcc version 3.3.1 (cygming special).

    Output:
    Zitat Zitat
    gcc -I/code/fltk-1.1.4/bin/include -mwindows -DWIN32 -mno-cygwin -o ShadowStuff3 ShadowStuff3.cxx -mwindows /code/fltk-1.1.4/bin/lib/libfltk.a -lole32 -luuid -lcomctl32 -lwsock32 -lsupc++

    ShadowStuff3.cxx: In function `char* damageEffects(int, int)':
    ShadowStuff3.cxx:129: warning: address of local variable `acharBuffer' returned
    damageEffects() hat nichts mit dem Programmteil zu tun, in dem der Fehler auftritt und funktioniert super.


    Ich probier's mal mit itoa().

    PS: Klappt. Stellt sich nur noch die Frage, warum sprintf() nicht mit enums klarkommt...

  4. #4
    wich ich Jeez schon per ICQ mitteile hab ich eine vermutung, woran das liegen koennte ... vielleicht interessierts den einen oder anderen ja cuh noch

    Die enums belegen wahrscheinlich nur so viel speicher, wie sie grade brauchen ... als in diesem codebeispiel 8 bit

    sprintf erwartet aber einen integer ... mit int in der regel als 32 bit ...

    somit ist dein enum fuer einen int wert 3 byte zu klein und der rest zeigt in der tat auf uninitialisierten speicher .. in dem fall bringt aber das malloc()en auch nixm, da du ja nur das eine byte mallocst

    Gruss Ineluki

  5. #5
    Und das ist es auch.
    Ich habe noch mal in den Stroustrup gesehen und dabei die Erklärung für das Verhalten gefunden (und wie ich mir dachte hat uninitialisierter Speicher eine Rolle gespielt). Ich zitiere:
    Zitat Zitat
    Der Bereich einer Aufzählung umfaßt alle seine Enumeratoren aufgerundet auf die nächstgrößere Zweierpotenz minus eins. Der Bereich geht herunter bis null, falls der kleinste Enumerator nicht negativ ist, und bis zur nächstkleineren Zweierpotenz plus eins sonst. Dadurch wird das kleinste Bitfeld, das die Werte der Enumeratoren speichern kann, definiert.
    Aus: "Die C++-Programmiersprache" von Bjarne Stroustrup, 3. Auflage
    Das wirkt erst mal ganz harmlos, bis man merkt: Dadurch wird auch definiert, wie viel Speicher für den Wert reserviert wird. Für die enums wurde bei mir grundsätzlich je 1 Byte reserviert, der Rest des Speichers, auf den sprintf() zugriff, war uninitialisiert.
    Wenn enmSpaces gemalloc()t gewesen wäre, hätte ich auch eine korrekte Ausgabe bekommen müssen.

    Merke: Wenn man mit enums arbeitet vorher alle Variablen, die mit ihnen in Kontakt kommen, initialisieren oder Funktionen verwenden, die sie in korrekte Integer umwandeln (oder wie solche behandeln).

  6. #6
    Das ergibt für mich aber keinen Sinn. Immerhin legst du ja mit 'int enmSpaces' ja genug Speicher für eine int-Variable an, und mit 'enmSpaces = S_Barrel|S_Top|S_Grip;' machst du einen impliziten Typecast auf Integer

    Ausserdem ergibt dieser Code
    Code:
    #include <stdio.h>
    
    enum { S_None = 0, S_Barrel = 1, S_Top = 2, S_Under = 4, S_Grip = 8, S_Stock = 16 }; //Spaces
    int enmSpaces;
    
    int main(void)
    {
      char * acharTempChar;
      acharTempChar = (char*) malloc(256);
      if(acharTempChar!=NULL)
      {
        sprintf(acharTempChar, "%i", enmSpaces);
        printf("%s",acharTempChar);
    		free(acharTempChar);
      }
    }
    ebenfalls 11. Zumindest, wenn ich es mit mingw übersetze.

  7. #7
    Daß ich einen int deklariere bedeutet nicht, daß auch der Speicher an der Stelle vorbereitet wird; sonst wäre malloc() überflüssig. Ich lege einfach fest, in welchen Speicherbereich ich was schreiben will.
    Wenn ich jetzt etwas wie int i = 5; mache führt C++ automatisch die richtige Operation (zero-fill) durch, damit aus dem Speicherbereich später auch ein Wert der Länge sizeof(int) mit dem Inhalt 5 gelesen werden kann.
    Wenn ich aber einen int mit dem Inhalt einer Enumeration fülle scheinen aber aus irgendeinem Grund nur so viele Bits geschrieben zu werden wie die Enumeration erfordert. itoa() und printf() scheinen das zu verstehen und den richtigen Wert zu extrahieren; sprintf() hingegen nicht.
    Anders kann ich es mir nicht vorstellen; FLTK ist eigentlich in der Lage, einen String zu handhaben.

  8. #8
    Zitat Zitat
    Original geschrieben von Jesus_666
    Daß ich einen int deklariere bedeutet nicht, daß auch der Speicher an der Stelle vorbereitet wird; sonst wäre malloc() überflüssig. Ich lege einfach fest, in welchen Speicherbereich ich was schreiben will.
    malloc wird auch nur verwendet, wenn du Speicher für ein struct oder ein Array anlegen willst (z.B: string = char-Array), wenn du einfach einen int deklarierst, wird genau ein int auch reserviert (angelegt natürlich bei initialisierung), oder hast du jemals malloc für i = 5 verwendet?
    Der Fehler liegt imo beim Compiler, denn dieser Code:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    enum { S_None = 0, S_Barrel = 1, S_Top = 2, S_Under = 4, S_Grip = 8, S_Stock = 16 }; //Spaces
    int enmSpaces;
    
    int main(void)
    {
    	enmSpaces = S_Barrel | S_Grip | S_Top;
    	char * acharTempChar;
    	acharTempChar = (char*) malloc(256);
    	if(acharTempChar!=NULL)
    	{
    		sprintf(acharTempChar, "%i", enmSpaces);
    		printf("%s\n",acharTempChar);
    		free(acharTempChar);
    	}
    
    }
    gibt bei mir 11 aus.

  9. #9
    Welche Version der GCC benutzt du? Cygwin und MinGW teilen sich einen Branch; es könnte also höchstens an der Version liegen.

    Ich weise auch wieder darauf hin, daß ich nicht printf() benutze und printf() sich nicht notwendig so verhält wie FL_Output::value(const char*). Ich weiß auch nicht, wie C++ sich verhält, wenn ich einen 8 Bit langen Wert in einen 64 Bit langen Speicherbereich schreibe.
    Ich weiß, daß ich per exit() den korrekten Wert zurückbekommen habe und daß ein per sprintf() übersetzter und an FL_Output::value(const char*) übergebener Wert zufällige Zahlen beinhaltete, die nach uninitialisiertem Speicher aussahen.

  10. #10
    Zitat Zitat
    Original geschrieben von Jesus_666
    [B]Welche Version der GCC benutzt du? Cygwin und MinGW teilen sich einen Branch; es könnte also höchstens an der Version liegen.
    3.1.0

  11. #11
    g++ --version
    g++ (GCC) 3.3.2 20031218 (Gentoo Linux 3.3.2-r5, propolice-3.3-7)

    cat ${MuabDibs Codestück} >> test.cpp

    $ g++ -o tester test.cpp
    $ ./tester
    11

    Code:
    $ cat test.cpp
    #include <stdio.h>
    #include <stdlib.h>
    
    enum { S_None = 0, S_Barrel = 1, S_Top = 2, S_Under = 4, S_Grip = 8, S_Stock = 16 };
    int enmSpaces;
    
    int main(void) {
            enmSpaces = S_Barrel|S_Top|S_Grip;
    
            char *acharTempChar;
            acharTempChar = (char*) malloc(256);
            if(acharTempChar!=NULL)
            {
                     sprintf(acharTempChar, "%i", enmSpaces);
                     //outG_Debug->value(acharTempChar);
                    printf("%s\n%i\n", acharTempChar, enmSpaces);
                     free(acharTempChar);
            }
    }
    cat $ABOVE > test.cpp

    $ g++ -o tester test.cpp
    $ ./tester
    11
    11

    Geändert von Master of Disaster (21.01.2004 um 23:19 Uhr)

  12. #12
    Wenn Version 3.1.0, 3.3.1 (cygming special) und 3.3.2 das gleiche Ergebnis liefern halte ich einen Compilerfehler für unwahrscheinlich.
    Es ist einfach irgendein Verhalten von Fl_Output::value(const char*), basta.

  13. #13
    hm .. gibt denn ein printf("%s\n",dein_string) das richtige ergebnis aus ? ... und vielleicht solltest du es ja auch nochmal mit einem
    for(int i=0; i<size_deines_strings_in_byte; i++) printf("%c",dein_string[i]); printf("/n");
    versuchen. Ist beides korrekt, kannst du davon ausgehen, das die umwandlung in einen string korrekt war und dann kann der fehler ja nicht in Fl_Output::value(const char*) liegen, den der string ist vom ersten bis letzten zeichen ja fest dimensioniert und auch gemalloc()t

    also bei mir geht ein print("%s\n",acharTempChar); ohne probleme und gibt mir 11 aus ... gcc version 2.95.3-6 (mingw special)

    ein for(int i=0; i<256; i++) printf("%x ",acharTempChar[i]); lieferte mir aber folgendes interessantes ergebnis ...
    Code:
    31 31 0 0 78 1 3d 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    Wenn man den String als nullterminiert betrachtet ist ja alles in ordnung. Wird er aber als Array of Char interpretiert (also nicht null terminiert) kommt da noch etwas datenmuell hinterher, obwohl er vorher gemalloc()t war ... vielleicht liegt da dein problem mit Fl_Output::value(const char*) ?

    ein explizites ZeroMemory(acharTempChar,256); direkt nach dem malloc()en loeste aber auch dieses problem

    Geändert von Ineluki (22.01.2004 um 22:30 Uhr)

  14. #14
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    enum { S_None = 0, S_Barrel = 1, S_Top = 2, S_Under = 4, S_Grip = 8, S_Stock = 16 }; //Spaces
    int enmSpaces;
    
    int main(void)
    {
    	enmSpaces = S_Barrel | S_Grip | S_Top;
    	char * acharTempChar;
    	acharTempChar = (char*) malloc(256);
    	if(acharTempChar!=NULL)
    	{
    		sprintf(acharTempChar, "%i", enmSpaces);
    		for(int i = 0; i < sizeof(acharTempChar); i++)
    		{
    			printf("%c",acharTempChar[i]);
    		}
    		free(acharTempChar);
    	}
    
    }
    Output:
    Code:
    C:\cmdprogs\cprogs>gcc -o tester.exe enum.cpp
    
    C:\cmdprogs\cprogs>tester
    11
    C:\cmdprogs\cprogs>
    nun...
    Zitat Zitat
    den der string ist vom ersten bis letzten zeichen ja fest dimensioniert und auch gemalloc()t
    Und ausserdem am Schluß der Zeichenkette mit dem obligatorischen 0-Byte versehen, um den String abzuschliessen. Gibt eigentlich Fl_Output::value(const char*) den String in irgendeiner anderen Weise aus bzw. ändert die Funktion etwas am String? Vielleicht kann es ja sein, dass das 0-Byte überschrieben wird.

    EDIT: Eine Minute zu spät ^^

  15. #15
    Nun... Das App wird ohne Konsolensupport kompiliert (-mwindows) und weigert sich, ohne -mwindows zu laufen. Mit printf() kriege ich nichts zurück.


    Ich habe mal MuadDibs Testprogramm zusammengeschraubt. und ein paar Tests mit verschiedenen Versionen gemacht.

    Ich teste in folgender Reihenfolge:
    hunzst: for(int i = 0; i < sizeof(acharTempChar); i++) { printf("%c",acharTempChar[i]); }
    hunzst2: for(int i = 0; i < sizeof(acharTempChar); i++) { printf("%x ",acharTempChar[i]); }
    hunzst3: for(int i = 0; i < 256; i++) { printf("%x ",acharTempChar[i]); }
    Code:
    $gcc -o hunzst hunzst.cxx && ./hunzst
    11
    $gcc -o hunzst2 hunzst2.cxx && ./hunzst2
    31 31 0 0
    $gcc -o hunzst3 hunzst3.cxx && ./hunzst3
    31 31 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

  16. #16
    Zitat Zitat
    Original geschrieben von Jesus_666
    Nun... Das App wird ohne Konsolensupport kompiliert (-mwindows) und weigert sich, ohne -mwindows zu laufen. Mit printf() kriege ich nichts zurück.
    Dann lass es in eine datei schreiben, sollte doch kein Problem fuer dich sein. ....

    So wie es aussieht, ist der string in ordnung ... aber wenn der string in ordnung ist, was soll dann dein FL_xyz::Value(blaa) denn noch falsch machen ...

    du koenntest noch ausprobieren, dass du nen neuen char* machst, den du mit der echten groesse des erhaltenen strings mallocst und dann den inhalt kopierst .... so dass der string wirklich nur als datenblock so viel inhalt hat, wie du brauchst .... wuerde mich aber wundern, wenn das was aendern wuerde

  17. #17
    Es könnte die chronische Müdigkeit sein, die momentan wieder aus mir spricht, aber ich denke, ich werde es eher pragmatisch angehen: Mit itoa() funzt es, also benutze ich itoa(). Fertig. *gähn*

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •