Elementlänge in <typedef enum>

  • Elementlänge in <typedef enum>

    Hallo!

    enum und typedef enum nehmen als Elementgröße ja immer int an.

    Ich bräuchte für die Anwendung unter ObjC die Möglichkeit, die Elementlänge explizit vorzugeben, z. B. uint8_t. Würde Folgendes funktionieren?

    Quellcode

    1. typedef enum uint8_t {
    2. MTYPE_RAW,
    3. MTYPE_STRING,
    4. MTYPE_DICT
    5. } MsgType;
    In Xcode werden die Elemente uint8_t und MsgType leider nicht automatisch eingefärbt, was mich schon einmal bedenklich stimmt, der Compiler wirft aber weder eine Warnung, noch einen Fehler.

    Danke!

    #EDIT
    Ich benötige das Ganze in einer Header-Struktur wie folgt:

    Quellcode

    1. typedef struct {
    2. uint8_t startdelimiter;
    3. uint8_t msg_type;
    4. uint32_t msg_length;
    5. uint8_t enddelimiter;
    6. } msg_header;
    Wenn das, was ich will, geht, soll sie später z. B. so aussehen:

    Quellcode

    1. typedef struct {
    2. MsgDelimiter startdelimiter;
    3. MsgType msg_type;
    4. uint32_t msg_length; // length without header
    5. MsgDelimiter enddelimiter;
    6. } msg_header;
  • Lustig :-), darauf bin auch schon gekommen - wie gesagt, der Compiler wirft keine Meldungen.

    Ich weiß bloß nicht, ob ich die Konstruktion richtig anwende oder nur auf einen nachsichtigen Compiler gestoßen bin, der sagt: Der Depp hat einen Fehler gemacht, ich gehe mal wieder auf den Standard mit int.
  • Ja, Danke Dir, den Beitrag kenne ich bereits. Der Knackpunkt ist folgender Passus:
    In C++, the underlaying type of an enumeration constant, and thus its size, is "implementation defined". This means it is defined by the compiler vendor. It shall be an intergal type and not be larger than an int unless the value cannot fit in an int or unsigned int.
    (C++ Standard, 7.2.5)

    In C99, the underlaying type of an enumeration constant is an int.
    Each *enumerated type* shall be compatible with an integer type. The choice of type is implementation-defined, but shall be capable of representing the values of all the members of the enumeration.
    (C99, 6.5.2.2)
    Daher mein Bezug auf das Verhalten in ObjC - vielleicht ist es hier ja (anders) definiert.
  • 1. Du kannst den Typen eines enums nicht selbst bestimmen (siehe auch Punkt 2). Den Typen MsgType, den du definierst, hat z.B. immer noch eine Grösse von 4 Byte:

    Quellcode

    1. NSLog(@"sizeof(MsgType) = %i", sizeof(MsgType));

    2. Du kannst auch nicht mit Sicherheit voraussagen, durch welchen Datentypen ein enum vom Compiler repräsentiert wird:
    Original vom C99-Standard
    open-std.org/JTC1/SC22/WG14/www/docs/n1425.pd; Kapitel 6.2.2; S.112

    6.7.2.2 Enumeration specifiers
    [...]
    2 The expression that defines the value of an enumeration constant shall be an integer constant expression that has a value representable as an int.
    [...]
    4 Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined,123) but shall be capable of representing the values of all the members of the enumeration. The enumerated type is incomplete until after the } that terminates the list of enumerator declarations.

    Das heisst, ein enum wird durch einen Typen repräsentiert, der maximal die Länge eines int hat (und ein int ist auch wieder von Plattform zu Plattform verschieden). Wenn der Compiler möchte, kann er aber auch nur ein char benutzen.


    3. Objective-C definiert das nicht anders:
    Original aus "The Objective-C 2.0 Programming Language"Objective-C is defined as a small but powerful set of extensions to the standard ANSI C language.


    4. Langer Rede kurzer Sinn: Was du willst, geht nicht.
  • Original von tps
    4. Langer Rede kurzer Sinn: Was du willst, geht nicht.
    Grmpf. Schon wieder.

    Aber ich könnte den msg_header, wie in meinem Ursprungszustand gezeigt, verwenden (also mit den uint8_t) und trotzdem mit den enum-Werten arbeiten, oder? Wenn ich einem 8-Bit-Wert einen 4-Byte-Wert zuweise, wird doch nur das niedrigste Byte verwendet, denke ich. Und ich kann ja kontrollieren, wieviele enum-Werte ich habe, so dass es keinen Überlauf gibt (sind eh nur drei). Das ist vermutlich nicht hübsch, aber irgendwie muss man das doch hinbekommen, ohne dass man die Werte des enums mit #defines behandelt ...

    Andere Frage: Kann ich etwas enum-ähnliches auch für Strings verwenden? Ich denke an die Keys für ein NSDictionary-Objekt, die an verschiedenen Stellen natürlich verwendet werden könn(t)en.
  • Quellcode

    1. typedef enum {
    2. MTYPE1_RAW,
    3. MTYPE1_STRING,
    4. MTYPE1_DICT
    5. } MsgType1;
    6. typedef enum {
    7. MTYPE2_RAW,
    8. MTYPE2_STRING,
    9. MTYPE2_DICT,
    10. meinPimmel = UINT64_MAX
    11. } MsgType2;
    12. NSLog( @"%d %d", sizeof( MsgType1 ), sizeof( MsgType2 ) );
    Alles anzeigen

    2010-01-24 18:07:13.879 Untitled[8575:a0f] 4 8


    Wenn das der Compiler nicht kann, dann meldet der sich schon …

    Zur Erläuterung:

    Wie bereits gesagt wurde, nimmt der Compiler nicht einen int, sondern eine Ganzzahl. Welche das ist, hat niemand gesagt. Es hat auch niemand gesagt, dass er einen bestimmten Ganzzahltypen nimmt.

    Daher muss ich ihn halt dazu zwingen, einen ausreichend großen zu nehmen. Und da wir bei ausreichend groß sind, landet eben mein Pimmel in deinem Enum.

    Steht aber auch bestimmt im Hillegass. ;)
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Original von fwtag
    @Amin:
    Interessant, was Du alles in MsgType2 steckst ... :)
    […]

    Tja, wer hat, der kann.

    Ich habe noch einmal eine Erläuterung für die Nachwelt eingefügt. Bleibt zu erwähnen, dass das zu der Kategorie von Problemen gehört, auf die ich eigentlich nur nach Nachweis der Volljährigkeit schreibe. Eigentlich sollte dich das nicht interessieren.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Original von fwtagAber ich könnte den msg_header, wie in meinem Ursprungszustand gezeigt, verwenden (also mit den uint8_t) und trotzdem mit den enum-Werten arbeiten, oder? Wenn ich einem 8-Bit-Wert einen 4-Byte-Wert zuweise, wird doch nur das niedrigste Byte verwendet, denke ich. Und ich kann ja kontrollieren, wieviele enum-Werte ich habe, so dass es keinen Überlauf gibt (sind eh nur drei). Das ist vermutlich nicht hübsch, aber irgendwie muss man das doch hinbekommen, ohne dass man die Werte des enums mit #defines behandelt ...

    Ja, mit Casting geht das schon. Schön ist es nicht.

    Original von fwtagAndere Frage: Kann ich etwas enum-ähnliches auch für Strings verwenden? Ich denke an die Keys für ein NSDictionary-Objekt, die an verschiedenen Stellen natürlich verwendet werden könn(t)en.

    Wie stellst du dir das vor? Als eine Art Array mit allen deinen Keys auf die du dann wiederum mit einem Index oder Schlüssel zugreifen musst? Da kannst du ja gleich die ursprünglichen Strings verwenden. Wenn du den gleichen String mehrmals verwendest, könntest du ihn z.B. als globale Konstante anlegen, dann hindert dich der Compiler daran, Schreibfehler zu begehen.

    @Amin: Er wollte aber einen kleineren Typen (1 Byte) als den, der standardmässig angelegt zu werden scheint (4 Byte). Das würde höchstens noch mit -fshort-enums gehen (auch nicht gerade ein Musterbeispiel an Eleganz).
  • Wie stellst du dir das vor? Als eine Art Array mit allen deinen Keys
    Mal anders herum gefragt: Wenn Ihr an verschiedenen Stellen im Code auf ein und dasselbe Dictionary zugreift, wie macht Ihr das dann mit den Keys? Immer @"..." für die Werte? Mal angenommen, ihr wollt den Key-Inhalt ändern, dann finde ich es schon elegant, wenn man das nur an einer Stelle machen muss. Ich habe das bisher immer mit #defines gemacht.

    Natürlich ist diese Betrachtung letztlich wurscht, wenn ich überall den Key - Neutraler oder Identifier - ändere, weil er mir nicht mehr gefällt.

    Ich versuche aber immer so abstrakt (Thema: elegant ...) wie möglich zu arbeiten: Wertdefinitionen wie Strings oder numerische Werte in abstrakte Identifier stecken und dann bei Bedarf halt nur an einer Stelle ändern. (Das ist für die Keys natürlich sehr akademisch gedacht, aber so mache ich es halt immer, egal ob Key oder sonstwas). Bisher hat sich dieser Ansatz auch sehr bewährt.
  • Original von fwtag
    Wie stellst du dir das vor? Als eine Art Array mit allen deinen Keys
    Mal anders herum gefragt: Wenn Ihr an verschiedenen Stellen im Code auf ein und dasselbe Dictionary zugreift, wie macht Ihr das dann mit den Keys? Immer @"..." für die Werte? Mal angenommen, ihr wollt den Key-Inhalt ändern, dann finde ich es schon elegant, wenn man das nur an einer Stelle machen muss. Ich habe das bisher immer mit #defines gemacht.

    Natürlich ist diese Betrachtung letztlich wurscht, wenn ich überall den Key - Neutraler oder Identifier - ändere, weil er mir nicht mehr gefällt.

    Ich versuche aber immer so abstrakt (Thema: elegant ...) wie möglich zu arbeiten: Wertdefinitionen wie Strings oder numerische Werte in abstrakte Identifier stecken und dann bei Bedarf halt nur an einer Stelle ändern. (Das ist für die Keys natürlich sehr akademisch gedacht, aber so mache ich es halt immer, egal ob Key oder sonstwas). Bisher hat sich dieser Ansatz auch sehr bewährt.

    Es gibt bei mir XYConstants.h und XYConstants.m. XY wechselt je nach Projekt
    So siehts in den Dateien aus:

    Quellcode

    1. Header
    2. extern const NSInteger UDDefaultPort;
    3. // keys in User Defaults
    4. extern NSString * const UDSplashScreenKey;

    Quellcode

    1. Code
    2. const NSInteger UDDefaultPort = 5222;
    3. // keys in User Defaults
    4. NSString * const UDSplashScreenKey = @"SplashScreen";


    Chris
    Man macht einfach solange irgendwelche Dinge, bis man tot ist.
    Und dann bekommen die anderen Kuchen.
  • Ok, ich folge widerwillig Euren Vorschlägen ;)

    Ich finde es aber trotzdem weder elegant, noch wirklich praktisch, mit zwei Dateien für eine Konstanten-Definition zu arbeiten. Eher lästige Doppelarbeit, aber wenn sich das nicht anders machen lässt, kann ich mich auf den Kopf stellen und mit den Füßen wackeln, ohne dass des einen Effekt hätte ...