Ich habe eine Datenstruktur wie diese:
struct foo { int id; int route; int backup_route; int current_route; }}
und eine Funktion namens update (), mit der Änderungen angefordert werden.
Update (42, dont_care, dont_care, new_route);
Das ist wirklich lang und wenn ich der Struktur etwas hinzufüge, muss ich JEDEM Aufruf zum Aktualisieren (...) ein 'dont_care' hinzufügen.
Ich denke darüber nach, stattdessen eine Struktur zu übergeben, aber das vorherige Ausfüllen der Struktur mit 'dont_care' ist noch mühsamer, als sie nur im Funktionsaufruf zu formulieren. Kann ich die Struktur irgendwo mit den Standardwerten von dont care erstellen und nur die Felder festlegen, die mir wichtig sind, nachdem ich sie als lokale Variable deklariert habe?
struct foo bar = {.id = 42, .current_route = new_route}; Update (& bar);
Was ist der eleganteste Weg, um nur die Informationen, die ich ausdrücken möchte, an die Aktualisierungsfunktion zu übergeben?
und ich möchte, dass alles andere standardmäßig -1 ist (der Geheimcode für 'egal')
quelle
PTHREAD_MUTEX_INITIALIZER
nutzt dies auch.Sie können Ihren geheimen Sonderwert in 0 ändern und die Standard-Semantik für Strukturelemente von C ausnutzen
wird dann 0 als Mitglieder der Leiste übergeben, die im Initialisierer nicht angegeben sind.
Oder Sie können ein Makro erstellen, das die Standardinitialisierung für Sie ausführt:
quelle
<stdarg.h>
Mit dieser Option können Sie verschiedene Funktionen definieren (die eine unbestimmte Anzahl von Argumenten akzeptieren, z. B.printf()
). Ich würde eine Funktion definieren, die eine beliebige Anzahl von Argumentpaaren verwendet, eines, das die zu aktualisierende Eigenschaft angibt, und eines, das den Wert angibt. Verwenden Sie eineenum
oder eine Zeichenfolge, um den Namen der Eigenschaft anzugeben.quelle
enum
Variablen demstruct
Feld zu? Hardcode es? Dann ist diese Funktion nur auf bestimmte anwendbarstruct
.Vielleicht sollten Sie stattdessen eine Präprozessor-Makrodefinition verwenden:
Wenn Ihre Instanz von (struct foo) global ist, brauchen Sie den Parameter dafür natürlich nicht. Aber ich gehe davon aus, dass Sie wahrscheinlich mehr als eine Instanz haben. Die Verwendung des Blocks ({...}) ist ein GNU-Ismus, der für GCC gilt. Es ist eine schöne (sichere) Möglichkeit, Linien als Block zusammenzuhalten. Wenn Sie später weitere Makros hinzufügen müssen, z. B. die Überprüfung der Bereichsüberprüfung, müssen Sie sich keine Sorgen mehr machen, dass Dinge wie if / else-Anweisungen usw. beschädigt werden.
Dies würde ich tun, basierend auf den von Ihnen angegebenen Anforderungen. Situationen wie diese sind einer der Gründe, warum ich viel mit Python angefangen habe. Der Umgang mit Standardparametern und dergleichen wird mit C viel einfacher als je zuvor (ich denke, das ist ein Python-Plug, sorry ;-)
quelle
Ein Musterobjekt, das verwendet wird, ist eine variable Funktion und Aufzählungswerte für jede Eigenschaft. Die Oberfläche sieht ungefähr so aus:
Das Schreiben einer Varargs-Funktion ist einfach - siehe http://www.eskimo.com/~scs/cclass/int/sx11b.html . Passen Sie einfach Schlüssel -> Wertepaare an und legen Sie die entsprechenden Strukturattribute fest.
quelle
Da es so aussieht, als ob Sie nur diese Struktur für die
update()
Funktion benötigen, verwenden Sie dafür überhaupt keine Struktur, da dies nur Ihre Absicht hinter diesem Konstrukt verschleiert. Sie sollten vielleicht überdenken, warum Sie diese Felder ändern und aktualisieren, und separate Funktionen oder Makros für diese "kleinen" Änderungen definieren.z.B
Oder schreiben Sie noch besser eine Funktion für jeden Änderungsfall. Wie Sie bereits bemerkt haben, ändern Sie nicht jede Eigenschaft gleichzeitig. Machen Sie es also möglich, jeweils nur eine Eigenschaft zu ändern. Dies verbessert nicht nur die Lesbarkeit, sondern hilft Ihnen auch bei der Behandlung der verschiedenen Fälle, z. B. müssen Sie nicht nach allen "dont_care" suchen, da Sie wissen, dass nur die aktuelle Route geändert wird.
quelle
Wie wäre es mit so etwas wie:
mit:
und:
und entsprechend:
In C ++ hat ein ähnliches Muster einen Namen, an den ich mich gerade nicht erinnere.
EDIT : Es heißt Named Parameter Idiom .
quelle
Ich bin verrostet mit Strukturen, daher fehlen mir hier wahrscheinlich ein paar Schlüsselwörter. Beginnen Sie jedoch mit einer globalen Struktur mit initialisierten Standardeinstellungen, kopieren Sie sie in Ihre lokale Variable und ändern Sie sie dann.
Ein Initialisierer wie:
Dann, wenn Sie es verwenden möchten:
quelle
Sie können das Problem mit einem X-Macro beheben
Sie würden Ihre Strukturdefinition ändern in:
Und dann können Sie einfach eine flexible Funktion definieren, auf die alle Felder gesetzt sind
dont_care
.Nach der Diskussion hier könnte man auch einen Standardwert auf diese Weise definieren:
Was bedeutet:
Und verwenden Sie es wie in hlovdal answer , mit dem Vorteil, dass hier die Wartung einfacher ist, dh die Änderung der Anzahl der Strukturelemente wird automatisch aktualisiert
foo_DONT_CARE
. Beachten Sie, dass das letzte "falsche" Komma akzeptabel ist .Ich habe das Konzept der X-Makros zum ersten Mal gelernt, als ich dieses Problem angehen musste .
Es ist äußerst flexibel, wenn neue Felder zur Struktur hinzugefügt werden. Wenn Sie unterschiedliche Datentypen haben, können Sie
dont_care
je nach Datentyp unterschiedliche Werte definieren : von hier aus können Sie sich von der Funktion inspirieren lassen, mit der die Werte im zweiten Beispiel gedruckt werden.Wenn Sie mit einer All-
int
Struktur einverstanden sind, können Sie den Datentyp weglassenLIST_OF_foo_MEMBERS
und einfach die X-Funktion der Strukturdefinition in ändern#define X(name) int name;
quelle
X
und normalerweise_ENTRY
an den Listennamen anzuhängen , z#define LIST_SOMETHING LIST_SOMETHING_ENTRY(a1, a2, aN) \ LIST_SOMETHING_ENTRY(b1, b2, bN) ...
.Der eleganteste Weg wäre, die Strukturfelder direkt zu aktualisieren, ohne die
update()
Funktion verwenden zu müssen - aber vielleicht gibt es gute Gründe für die Verwendung, die in der Frage nicht vorkommen.Oder Sie können, wie von Pukku vorgeschlagen, separate Zugriffsfunktionen für jedes Feld der Struktur erstellen.
Ansonsten ist die beste Lösung, die ich mir vorstellen kann, einen Wert von '0' in einem Strukturfeld als 'Nicht aktualisieren' -Flag zu behandeln. Sie erstellen also einfach eine Funktion, um eine auf Null gesetzte Struktur zurückzugeben, und verwenden diese dann zum Aktualisieren.
Dies ist jedoch möglicherweise nicht sehr realisierbar, wenn 0 ein gültiger Wert für Felder in der Struktur ist.
quelle