Verständisfrage zu C Strings



  • Ich habe ein kleines Verständnisproblem in Sachen C Strings. Und zwar wollte ich gerne einen C String als Menge von XML-Unicodes-Zeichen darstellen. Dabei habe ich folgendes gemacht

    voit PrintStringAsXML(const char* String)
    {
      char HexString[8];
      char c;
    
      printf("Original String: %s\n", String);
      printf("XML String: ");
      while (*String != 0)
      {
        c = *String;
        sprintf(HexString, "&#x%X;", c);
        printf(HexString);
        String++;
      }
      printf("\n");
    }
    

    Der Code hat einen Fehler. Und zwar muss die Variable c vom Typ unsigned char sein, da sonst beispielsweise Zeichen wie 'ß' als Zahlenwert -33 sind und nicht 223.

    Also müsste man doch, wenn man sauber programmieren möchte, einen String als unsigned char* definieren. Nichtsdestotrotz habe ich bisher immer nur char* als Definition gesehen.

    Warum ist das so ? 😕



  • char ist eben der Datentyp für Zeichen. char muss auch nicht vorzeichenbehaftet sein. Aber auch wenn das bei deinem Compiler der Fall ist: da -33 die gleiche Binärdarstellung wie 223 hat, ist es letztendlich egal. Wenn du Zeichen aber als positive Zahlen behandeln möchtest, kannst du nach unsigned casten.



  • char ist eben der Datentyp für Zeichen.

    Und ich glaube dass das gerade nicht der Fall ist (siehe unter anderem an den Befehlen getc(), isalnum(),...). Denn das Hauptproblem was ich hier habe ist die fehlende Typsicherheit.

    Der Code ist genau deswegen fehlerhaft weil er beim sprintf Befehl die übergebene Variable c eben als Datentyp für Zahlen zwischen -127 und 128 interpretiert. Und anscheinend castet er implizit den übergebenen Wert in ein Integer um, und blub ist -33 binär auf einmal was anderes als 223.

    Wüsste der Compiler das c ein Zeichen ist, würde er intern das Ganze als Ascii Code interpretieren und dann den sprintf Befehl ausführen.

    char muss auch nicht vorzeichenbehaftet sein.

    Ich hoffe dass das falsch ist. 🙂 Ansonsten wiederspräche dies der Definition von char.



  • void PrintStringAsXML(const char* String)
    {
      char HexString[8];
    
      printf("Original String: %s\n", String);
      printf("XML String: ");
    
      while( *String )
      {
        sprintf(HexString, "&#x%X;", *String++);
        printf(HexString);
      }
      printf("\n");
    }
    

    ASCII ist eine 7-Bit Zeichenkodierung ... denk mal druf rum.


  • Mod

    Bitte ein Bit schrieb:

    char ist eben der Datentyp für Zeichen.

    Und ich glaube dass das gerade nicht der Fall ist (siehe unter anderem an den Befehlen getc(), isalnum(),...). Denn das Hauptproblem was ich hier habe ist die fehlende Typsicherheit.

    Was du glaubst und was ist, sind sehr verschiedene Sachen. char ist für Zeichen. unsigned char und signed char sind zum Rechnen mit kleinen Zahlen.

    Der Code ist genau deswegen fehlerhaft weil er beim sprintf Befehl die übergebene Variable c eben als Datentyp für Zahlen zwischen -127 und 128 interpretiert. Und anscheinend castet er implizit den übergebenen Wert in ein Integer um, und blub ist -33 binär auf einmal was anderes als 223.

    c ist ja auch vom Typ char und anscheinend ist dieser Typ bei dir vorzeichenbehaftet. Und da du sprintf explizit sagst, dass der Wert als unsigned int aufgefasst werden soll (%X), wird das dann natürlich auch als unsigned int mit Wert -33 aufgefasst. Was hättest du denn sonst erwartet? Wenn du das nicht willst, dann musst du eben wie du selbst festgestellt hast mit unsigned chars arbeiten (oder vorher nach unsigned char casten).

    Wüsste der Compiler das c ein Zeichen ist, würde er intern das Ganze als Ascii Code interpretieren und dann den sprintf Befehl ausführen.

    😕 Du hast komische Vorstellungen wie das intern funktioniert. Alles ist Zahl. Es gibt kein internes ASCII. Und du hast hier dem Compiler eindeutig gesagt, dass du eine negative Zahl als unsigned int aufgefasst haben möchtest. Und das macht er dann natürlich auch.

    char muss auch nicht vorzeichenbehaftet sein.

    Ich hoffe dass das falsch ist. 🙂 Ansonsten wiederspräche dies der Definition von char.

    Ist aber so. Und inwiefern widerspräche das der Definition? Die Definition ist, dass ein char ein Datentyp ist, der den Zeichensatz der Implementierung fassen kann. Ich sehe da nichts über Vorzeichen.



  • @Alle
    Bitte nicht ärgern wenn ich so dumm rumfrage. Ich habe bloß char als einen 1 Byte Datentyp kennegelernt, welcher Zahlen zwischen -127 und 128 aufnehmen kann. 😞

    Ich sehe jetzt zum ersten Mal dass char, signed char und unsigned char unterschiedliche Datentypen sind. http://msdn.microsoft.com/en-us/library/cc953fe1%28VS.80%29.aspx

    ----------------------------------

    Sepp schrieb:

    Was du glaubst und was ist, sind sehr verschiedene Sachen. char ist für Zeichen. unsigned char und signed char sind zum Rechnen mit kleinen Zahlen.

    Und da würde ich mir halt eine Warning Meldung wünschen wenn ich einem char eine Zahl zuweise...

    Sepp schrieb:

    c ist ja auch vom Typ char und anscheinend ist dieser Typ bei dir vorzeichenbehaftet. Und da du sprintf explizit sagst, dass der Wert als unsigned int aufgefasst werden soll (%X), wird das dann natürlich auch als unsigned int mit Wert -33 aufgefasst. Was hättest du denn sonst erwartet? Wenn du das nicht willst, dann musst du eben wie du selbst festgestellt hast mit unsigned chars arbeiten (oder vorher nach unsigned char casten).

    Hast Recht. Ich hatte bloß vergessen das sprintf wohl aufgrund des Formatstrings die Parameter interpretiert.



  • implizit sind alle integralen Datentypen signed. "unsigned" muss explizit angegeben werden.



  • FrEEzE2046 schrieb:

    implizit sind alle integralen Datentypen signed. "unsigned" muss explizit angegeben werden.

    Wie oben bereits gesagt ist das eben nicht so. Die Ausnahme ist char.



  • Tim schrieb:

    Wie oben bereits gesagt ist das eben nicht so. Die Ausnahme ist char.

    Nun, dass ist laut Standard ja definitionsabhängig oder was meinst du?

    limits.h:

    #define CHAR_BIT      8         /* number of bits in a char */
    #define SCHAR_MIN   (-128)      /* minimum signed char value */
    #define SCHAR_MAX     127       /* maximum signed char value */
    #define UCHAR_MAX     0xff      /* maximum unsigned char value */
    
    #ifndef _CHAR_UNSIGNED
    #define CHAR_MIN    SCHAR_MIN   /* mimimum char value */
    #define CHAR_MAX    SCHAR_MAX   /* maximum char value */
    #else
    #define CHAR_MIN      0
    #define CHAR_MAX    UCHAR_MAX
    #endif  /* _CHAR_UNSIGNED */
    


  • FrEEzE2046 schrieb:

    Tim schrieb:

    Wie oben bereits gesagt ist das eben nicht so. Die Ausnahme ist char.

    Nun, dass ist laut Standard ja definitionsabhängig oder was meinst du?

    Genau das meine ich.



  • Die relevante Stelle im Standard liest sich so:

    ISO/IEC 9889:1999, 6.2.5 schrieb:

    13 The three types char, signed char, and unsigned char are collectively called the character types. **The implementation shall define char to have the same range, representation, and behavior as either signed char or unsigned char.**35)

    Fußnote 35: CHAR_MIN, defined in <limits.h>, will have one of the values 0 or SCHAR_MIN, and this can be used to distinguish the two options. Irrespective of the choice made, char is a separate type from the other two and is not compatible with either.

    Hervorhebung von mir.

    Dabei ist char übrigens nicht auf ASCII festgelegt. Der Standard garantiert lediglich Folgendes:

    ISO/IEC 9889:1999, 6.2.5 schrieb:

    3 An object declared as type char is large enough to store any member of the basic execution character set. If a member of the basic execution character set is stored in a char object, its value is guaranteed to be nonnegative. If any other character is stored in a char object, the resulting value is implementation-defined but shall be within the range of values that can be represented in that type.

    Das basic execution character set ist implementationsabhängig (5.2.1 (1)), wobei eine Reihe von Dingen darüber garantiert werden. Seinerzeit wird damit vor allem gemeint gewesen sein, dass die Implementation entscheidet, ob sie ASCII oder EBCDIC benutzt.


Anmelden zum Antworten