Enum mit Pointern in C

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Enum mit Pointern in C

    Ha, da hab ich aber grad noch mal die Kurve gekriegt. :D
    Ernsthaft, da sich Swift auf einem aufsteigenden und Objective–C auf einem absterbenden Ast befindet, wäre ich dafür, statt einem 'Swift' lieber ein 'Objective-C' Unterforum anzubieten.
    Aber zum Glück kann ich ausweichen. ;)

    Also inspiriert von Swift (es ist ja nicht NUR Scheiße, sondern nur zu 80%) wäre ich schon gern dafür, enum nicht nur auf dusselige skalare Datentypen anwenden zu können, sondern auch auf Objekte.
    Klassisches Beispiel: JSON Parser. Ich parse mich durch gefühlt 5000 Attribute des JSON API Objekts und wundere mich, dass meine Implementierung für einen Key einfach nicht aufgerufen wird, obwohl der Key gesetzt wird.
    Typisches Phänomen: Ich habe den Key hochdynamisch bereits sieben Bildschirme vorher implementiert.

    Mit switch wäre das nicht passiert, das hätte mich gewarnt, dass ich da einen Key doppelt verwurste.
    Nun würde ich dieses sinnvolle Feature gern für mich nutzen. (Baut Apple zufällig im Hinterstübchen an Objective-C 3.0 und nutzt Swift nur als Übungsplattform?)
    Nur: Wie?

    Ein Enum in C kann ja nicht viel anderes sein als eine Ganzzahl.
    Natürlich kann ich meine 5000 Keys in ein Array packen und die Indices in einem Enum verwursten. Dann müsste ich nur zusehen, dass ich diesen Index im Switch abarbeite und kümmere mich dann gar nicht weiter um den genannten Key.

    Aber… Gibt es da nichts Eleganteres? 8|
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • Ich verwende in Objective-C für solche Probleme häufig dynamische Nachrichten, in dem ich aus dem Schlüssel einen Methodennamen erzeuge (z. B. Präfix oder Suffix einfügen). Mit NSSelectorFromString wandle ich das in einen Selector um, den ich dann an irgendein Objekt senden kann.
    „Meine Komplikation hatte eine Komplikation.“
  • macmoonshine schrieb:

    Ich verwende in Objective-C für solche Probleme häufig dynamische Nachrichten, in dem ich aus dem Schlüssel einen Methodennamen erzeuge (z. B. Präfix oder Suffix einfügen). Mit NSSelectorFromString wandle ich das in einen Selector um, den ich dann an irgendein Objekt senden kann.
    Geht zwar, sowas mache ich aber extrem ungerne, besonders mit Daten die von draußen kommen. Weil: Potenziell kann man damit auch ungewünschte Pfade öffnen.

    Warum nicht ein Dictionary mit Key->Handler? Handler kann ein Selector, eine Invocation, ein Parserobjekt nach eigenem Interface, ein Block oder sonstwas sein, frei nach Anforderungen und Geschmack.
    Multigrad - 360°-Produktfotografie für den Mac
  • Amin Negm-Awad schrieb:

    Mal abgesehen davon, dass ich glaube, dass da ein ellenlanger Text steht, der zwei Sätze sinnvoller Aussage enthält, verwendet man keine Enums, sondern Strings.
    +badunz+
    Und wie verhinderst Du, dass Du den String @"type" 17x abfragst und 17x anders behandelst?
    Trifft übrigens auch auf Thallius zu.

    Ob ich jetzt 17x @"type" abfrage und anders behandle, oder 17x (k)JSONAPIResourceObjectTypeKey abfrage und anders behandle, ändert nichts an dem Grundproblem, dass ich einen wie auch immer gearteten String 17x abfrage und anders behandle, weil mich der Compiler hier stumpf nicht unterstützt.

    [mattik]
    Sehr schöner und sehr dynamischer Ansatz. :)

    Statt also dem ursprünglichen Ansatz hinterherzulaufen:

    Quellcode

    1. switch( [self indexForKeyPath:key) {
    2. case JSONAPIResourceKeyPathIndexID:
    3. [object setID:value];
    4. break;
    5. // … und das für die nächsten 499 Möglichkeiten
    6. }

    Sollte ich das ganze eher weiter dynamisieren, beispielsweise:
    [object performSelector: [handlerDictionary objectForKey:key] withObject:value]; // Jaja, ich weiß. ARC will wissen welcher Thread.

    Danke!
    Für solche Erleuchtung nehme ich Amins unqualifiziertes Gefrotzel gern auf mich. =D
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • mattik schrieb:

    macmoonshine schrieb:

    Ich verwende in Objective-C für solche Probleme häufig dynamische Nachrichten, in dem ich aus dem Schlüssel einen Methodennamen erzeuge (z. B. Präfix oder Suffix einfügen). Mit NSSelectorFromString wandle ich das in einen Selector um, den ich dann an irgendein Objekt senden kann.
    Geht zwar, sowas mache ich aber extrem ungerne, besonders mit Daten die von draußen kommen. Weil: Potenziell kann man damit auch ungewünschte Pfade öffnen.
    Warum nicht ein Dictionary mit Key->Handler? Handler kann ein Selector, eine Invocation, ein Parserobjekt nach eigenem Interface, ein Block oder sonstwas sein, frei nach Anforderungen und Geschmack.
    Habe ich neulich auch einem Kunden im Hochsicherheitsbereich (Bankenkommunikation) gesagt und ihm geraten es explizit zu machen. Aber in der Regel findet die Sicherung ja auf einem anderen Layer statt.

    Eine einfache Hausmacherlösung ist übrigens ein Set zurückzuliefern, welches die legalen Keys enthält.
    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"?
  • macmoonshine schrieb:

    Ich verwende in Objective-C für solche Probleme häufig dynamische Nachrichten, in dem ich aus dem Schlüssel einen Methodennamen erzeuge (z. B. Präfix oder Suffix einfügen). Mit NSSelectorFromString wandle ich das in einen Selector um, den ich dann an irgendein Objekt senden kann.
    Könnte man fast KVC nennen. :)
    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"?
  • Amin Negm-Awad schrieb:

    macmoonshine schrieb:

    Ich verwende in Objective-C für solche Probleme häufig dynamische Nachrichten, in dem ich aus dem Schlüssel einen Methodennamen erzeuge (z. B. Präfix oder Suffix einfügen). Mit NSSelectorFromString wandle ich das in einen Selector um, den ich dann an irgendein Objekt senden kann.
    Könnte man fast KVC nennen. :)
    Oder so ;)


    mattik schrieb:

    macmoonshine schrieb:

    Ich verwende in Objective-C für solche Probleme häufig dynamische Nachrichten, in dem ich aus dem Schlüssel einen Methodennamen erzeuge (z. B. Präfix oder Suffix einfügen). Mit NSSelectorFromString wandle ich das in einen Selector um, den ich dann an irgendein Objekt senden kann.
    Geht zwar, sowas mache ich aber extrem ungerne, besonders mit Daten die von draußen kommen. Weil: Potenziell kann man damit auch ungewünschte Pfade öffnen.
    Warum nicht ein Dictionary mit Key->Handler? Handler kann ein Selector, eine Invocation, ein Parserobjekt nach eigenem Interface, ein Block oder sonstwas sein, frei nach Anforderungen und Geschmack.
    Ja, deswegen die Prä- und/oder Suffixe. Die sollte man so wählen, dass sie eine Überschneidung mit anderen Methoden ausschließen.
    „Meine Komplikation hatte eine Komplikation.“
  • Amin Negm-Awad schrieb:

    Habe ich neulich auch einem Kunden im Hochsicherheitsbereich (Bankenkommunikation) gesagt und ihm geraten es explizit zu machen. Aber in der Regel findet die Sicherung ja auf einem anderen Layer statt.

    Eine einfache Hausmacherlösung ist übrigens ein Set zurückzuliefern, welches die legalen Keys enthält.
    Eine weitere Sicherungsschicht ist schön und gut (und in sicherheitskritischen Anwendungen sicherlich eine gute Idee), aber das darf ja keine Ausrede dafür sein, dass der Parser nicht ordentlich validiert. Und wenn ich eh ein Set mit legalen Keys brauche, kann ich auch gleich ein Dictionary bauen, in dem dann auch steht, wie der Key zu behandeln ist - dann hat man das alles schön an einem Ort (das Set kann man dann ja trivial über [NSSet setWithArray:dict.allKeys] ableiten - warum gibt NSDictionary da eigentlich ein Array zurück?).

    Beides machbar - ich finde da den expliziten Weg ordentlicher. Die Laufzeitdynamik von ObjC ist toll, aber ich benutze sie nur in Fällen, in denen es keine vergleichbar einfache Alternative gibt. Implizites Laufzeitzeug hat immer das Potenzial, einem irgendwann auf die Füße zu fallen.
    Multigrad - 360°-Produktfotografie für den Mac
  • macmoonshine schrieb:

    Amin Negm-Awad schrieb:

    macmoonshine schrieb:

    Ich verwende in Objective-C für solche Probleme häufig dynamische Nachrichten, in dem ich aus dem Schlüssel einen Methodennamen erzeuge (z. B. Präfix oder Suffix einfügen). Mit NSSelectorFromString wandle ich das in einen Selector um, den ich dann an irgendein Objekt senden kann.
    Könnte man fast KVC nennen. :)
    Oder so ;)

    mattik schrieb:

    macmoonshine schrieb:

    Ich verwende in Objective-C für solche Probleme häufig dynamische Nachrichten, in dem ich aus dem Schlüssel einen Methodennamen erzeuge (z. B. Präfix oder Suffix einfügen). Mit NSSelectorFromString wandle ich das in einen Selector um, den ich dann an irgendein Objekt senden kann.
    Geht zwar, sowas mache ich aber extrem ungerne, besonders mit Daten die von draußen kommen. Weil: Potenziell kann man damit auch ungewünschte Pfade öffnen.Warum nicht ein Dictionary mit Key->Handler? Handler kann ein Selector, eine Invocation, ein Parserobjekt nach eigenem Interface, ein Block oder sonstwas sein, frei nach Anforderungen und Geschmack.
    Ja, deswegen die Prä- und/oder Suffixe. Die sollte man so wählen, dass sie eine Überschneidung mit anderen Methoden ausschließen.
    Klar geht das, aber wozu? Da holt man sich jede Menge Laufzeitoverhead und Namenskonventionen ins Boot, bei denen man nach drei Monaten wieder nachschauen muss, was man da angestellt hat - nur um sich eine Lookuptabelle zu ersparen? Hmmm...
    Multigrad - 360°-Produktfotografie für den Mac
  • Marco Feltmann schrieb:

    Amin Negm-Awad schrieb:

    Mal abgesehen davon, dass ich glaube, dass da ein ellenlanger Text steht, der zwei Sätze sinnvoller Aussage enthält, verwendet man keine Enums, sondern Strings.
    +badunz+Und wie verhinderst Du, dass Du den String @"type" 17x abfragst und 17x anders behandelst?
    Trifft übrigens auch auf Thallius zu.

    Ob ich jetzt 17x @"type" abfrage und anders behandle, oder 17x (k)JSONAPIResourceObjectTypeKey abfrage und anders behandle, ändert nichts an dem Grundproblem, dass ich einen wie auch immer gearteten String 17x abfrage und anders behandle, weil mich der Compiler hier stumpf nicht unterstützt.

    [mattik]
    Sehr schöner und sehr dynamischer Ansatz. :)

    Statt also dem ursprünglichen Ansatz hinterherzulaufen:

    Quellcode

    1. switch( [self indexForKeyPath:key) {
    2. case JSONAPIResourceKeyPathIndexID:
    3. [object setID:value];
    4. break;
    5. // … und das für die nächsten 499 Möglichkeiten
    6. }
    Sollte ich das ganze eher weiter dynamisieren, beispielsweise:
    [object performSelector: [handlerDictionary objectForKey:key] withObject:value]; // Jaja, ich weiß. ARC will wissen welcher Thread.

    Danke!
    Für solche Erleuchtung nehme ich Amins unqualifiziertes Gefrotzel gern auf mich. =D
    warum willst du die 500 keys überhaupt manuell abarbeiten?
    warum nicht einfach ein [setJsonValue: forKey:[NSNumber numberWithInteger:enumvalue]] ?
  • btw:

    führe mal den code aus und staune ;)

    Quellcode

    1. @import Foundation;
    2. #define MyEnumValues(GENERATOR) \
    3. GENERATOR( TypeUnknown, 0) \
    4. GENERATOR( TypeAll, 1) \
    5. GENERATOR( TypeLibrary, 2) \
    6. GENERATOR( TypeUnused, 3) \
    7. GENERATOR( TypeSet, 4) \
    8. GENERATOR( TypeFolder, 5) \
    9. #define GENERATOR_ENUM(name, value) name = value,
    10. #define GENERATOR_SWITCH(name, value) case value: return @#name;
    11. #define GENERATOR_ALL_NAMES(name, value) @#name,
    12. #define GENERATOR_ALL(name, value) @#name,@value,
    13. typedef enum MyEnum
    14. {
    15. MyEnumValues(GENERATOR_ENUM)
    16. } MyEnum;
    17. NSString *NameForEnum(MyEnum e)
    18. {
    19. switch (e)
    20. {
    21. MyEnumValues(GENERATOR_SWITCH)
    22. }
    23. return nil;
    24. }
    25. NSArray *AllEnumNames()
    26. {
    27. static NSArray *allNames = nil;
    28. if (!allNames)
    29. {
    30. allNames = [[NSArray alloc] initWithObjects:MyEnumValues(GENERATOR_ALL_NAMES) nil];
    31. }
    32. return allNames;
    33. }
    34. NSDictionary *AllEnums()
    35. {
    36. static NSDictionary *allEnums = nil;
    37. if (!allEnums)
    38. {
    39. allEnums = [[NSDictionary alloc] initWithObjectsAndKeys:MyEnumValues(GENERATOR_ALL) nil];
    40. }
    41. return allEnums;
    42. }
    43. int main(int argc, const char * argv[])
    44. {
    45. @autoreleasepool
    46. {
    47. NSLog(@"AllEnumNames: %@", AllEnumNames());
    48. NSLog(@"AllEnums: %@", AllEnums());
    49. NSLog(@"NameForEnum TypeLibrary: %@", NameForEnum(TypeLibrary));
    50. NSLog(@"NameForEnum TypeFolder: %@", NameForEnum(TypeFolder));
    51. }
    52. return 0;
    53. }
    Alles anzeigen

    edit: der code nach dem preprocessing sieht übrigens so aus (erspart dir also das ganze getippe):

    Quellcode

    1. typedef enum MyEnum
    2. {
    3. TypeUnknown = 0, TypeAll = 1, TypeLibrary = 2, TypeUnused = 3, TypeSet = 4, TypeFolder = 5,
    4. } MyEnum;
    5. NSString *NameForEnum(MyEnum e)
    6. {
    7. switch (e)
    8. {
    9. case 0: return @"TypeUnknown"; case 1: return @"TypeAll"; case 2: return @"TypeLibrary"; case 3: return @"TypeUnused"; case 4: return @"TypeSet"; case 5: return @"TypeFolder";
    10. }
    11. return ((void *)0);
    12. }
    13. NSArray *AllEnumNames()
    14. {
    15. static NSArray *allNames = ((void *)0);
    16. if (!allNames)
    17. {
    18. allNames = [[NSArray alloc] initWithObjects:@"TypeUnknown", @"TypeAll", @"TypeLibrary", @"TypeUnused", @"TypeSet", @"TypeFolder", ((void *)0)];
    19. }
    20. return allNames;
    21. }
    22. NSDictionary *AllEnums()
    23. {
    24. static NSDictionary *allEnums = ((void *)0);
    25. if (!allEnums)
    26. {
    27. allEnums = [[NSDictionary alloc] initWithObjectsAndKeys:@"TypeUnknown",@0, @"TypeAll",@1, @"TypeLibrary",@2, @"TypeUnused",@3, @"TypeSet",@4, @"TypeFolder",@5, ((void *)0)];
    28. }
    29. return allEnums;
    30. }
    Alles anzeigen
  • mattik schrieb:

    Schick, aber da wäre mir ObjC-Runtime-Voodoo noch lieber als define-Voodoo...
    bekommt man das damit hin?
    ich möchte natürlich mit den raw enum values arbeiten und nicht mit irgendwelchen NSNumber oder NSString objekten

    edit: ich verwende es übrigens in code der für Mac und Windows verwendet wird.
    In C++ und Obj-c (und zum Generieren der doku werden auch die defines verwendet (der text der in der doku stehen soll kann also direkt hinter den enum-wert geschrieben werden)).
  • Ich glaube dir, dass das bestimmt für irgendwas gut ist. Mir fällt nur gerade nicht ein, wann ich sowas gebraucht habe. Immer wenn ich an eine Stelle gestoßen bin, an der ich mir sowas gewünscht hätte, habe ich gemerkt, dass irgendwas mit meinem Design nicht stimmt. Das kann aber an mir liegen.

    Mit defines kann man tolle Sachen machen. U.a. sich selbst gehörig ins Knie schießen. Das versteht kein Projekteinsteiger und ich selbst nach drei Monaten auch nicht mehr. Und die aus einem falschen Zeichen darin resultierenden Fehlermeldungen auch nicht.

    Verstehe mich nicht falsch: Ich finde defines super, verwende sie aber nur, wenn es absolut nicht anders geht (z.B. manchmal in Embedded-Code). Aber gerade verschachtelte Markos können sich übel rächen.
    Multigrad - 360°-Produktfotografie für den Mac
  • mattik schrieb:

    Mit defines kann man tolle Sachen machen. U.a. sich selbst gehörig ins Knie schießen. Das versteht kein Projekteinsteiger und ich selbst nach drei Monaten auch nicht mehr. Und die aus einem falschen Zeichen darin resultierenden Fehlermeldungen auch nicht.

    hehe, das ist sicher - und sogar von hinten durch die brust ins auge!

    naja, die fehlermeldungen versteht man sehr schnell wenn man sich den code anzeigen lässt den der preprozessor erstellt hat (ist in Xcode ja nur ein klick oder zwei).

    aber ansonsten hast du natürlich recht und ich verwende es auch nur in dem speziellen fall...

    ob der threadstarter dann sowas verwendet oder nicht muss er selbst wissen ;)

    btw: mit vernünftigen macro-namen ist das gleich ein stück übersichtlicher (wie immer).

    so und jetzt ruft das feierabendbier!
  • mattik schrieb:

    Amin Negm-Awad schrieb:

    Habe ich neulich auch einem Kunden im Hochsicherheitsbereich (Bankenkommunikation) gesagt und ihm geraten es explizit zu machen. Aber in der Regel findet die Sicherung ja auf einem anderen Layer statt.

    Eine einfache Hausmacherlösung ist übrigens ein Set zurückzuliefern, welches die legalen Keys enthält.
    Eine weitere Sicherungsschicht ist schön und gut (und in sicherheitskritischen Anwendungen sicherlich eine gute Idee), aber das darf ja keine Ausrede dafür sein, dass der Parser nicht ordentlich validiert. Und wenn ich eh ein Set mit legalen Keys brauche, kann ich auch gleich ein Dictionary bauen, in dem dann auch steht, wie der Key zu behandeln ist - dann hat man das alles schön an einem Ort (das Set kann man dann ja trivial über [NSSet setWithArray:dict.allKeys] ableiten - warum gibt NSDictionary da eigentlich ein Array zurück?).
    Beides machbar - ich finde da den expliziten Weg ordentlicher. Die Laufzeitdynamik von ObjC ist toll, aber ich benutze sie nur in Fällen, in denen es keine vergleichbar einfache Alternative gibt. Implizites Laufzeitzeug hat immer das Potenzial, einem irgendwann auf die Füße zu fallen.
    Mir fällt jetzt die Erwiderung etwas schwer, denn das alles habe ich dem Kunden auch gesagt. :) Insbesondere waren dann Validierungsregeln schwierig zu formulieren und gingen so weit, dass wenn Schlüssel A den Wert X hat, dann muss der Schlüssel B existieren und so weiter. Ich sagte ihm dann: "Du kannst dir jetzt für die ganze Validierung eine DSL ausdenken, darin die Regeln formulieren und hast es dann sicher. Aber halt, du hast ja schon eine Sprache in der du die Regeln formulieren kannst: Objective-C. Wieso willst du also dir eine neue ausdenken, um das in Objective-C generisch zu formulieren und dann wieder in MySupiDupiDSL wieder zu konkretisieren?"

    Aber du sprichst es selbst an: Es gibt Grenzen. Bei Objective-Cloud können wir nicht applikationsspezifisch validieren. Logisch. Deshalb haben wir ja einen Compiler gebaut, der aus der Source wenigstens das herausholt, was drin steht. Ist ein Parameter etwa auf NSNumber* typisiert, darf da im JSON auch kein String stehen. Ist das auf Person* typisiert, darf da kein Gruppen-Objekt kommen usw. So würde man es ja auch innerhalb einer Applikation erwarten.

    Alles darüber hinaus könnte man jetzt sicherlich noch zu einem Gutteil mit irgendwas.config erschlagen können. Wollen wir nicht. Auf keinen Fall. Wenn es weitere Constraints gibt, sind die im Code zu schreiben. In der Sprache, die der Programmierer beherrscht: Objective-C.

    Alles andere ist Java.
    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"?
  • mattik schrieb:

    Klar geht das, aber wozu? Da holt man sich jede Menge Laufzeitoverhead und Namenskonventionen ins Boot, bei denen man nach drei Monaten wieder nachschauen muss, was man da angestellt hat - nur um sich eine Lookuptabelle zu ersparen? Hmmm...
    Ich sage ja nicht, dass es immer der optimale Weg ist. Allerdings juckt mir bei deiner Argumentation ein POITROAE in den Fingern, und dass eine Lookuptabelle wirklich schneller ist, sagt sich auch schnell daher. Die Namenskonventionen können nach drei Monaten Abstinenz sogar hilfreich sein. ;)
    „Meine Komplikation hatte eine Komplikation.“