Konstruktor für Strukturen in C

Lesezeit: 4 Minuten

Gegeben:

struct objStruct {
    int id;
    int value;
};

typedef struct objStruct Object;

Gibt es eine Verknüpfung zum Zuweisen und Initialisieren des Objekts, so etwas wie einen C++-Konstruktor?
Es könnte sogar ein Präprozessor-Makro sein. Was auch immer den Code kürzer und lesbarer macht als dies:

Object *newObj = malloc(sizeof(Object));
// successful allocation test snipped
newObj->id = id++;
newObj->value = myValue;

  • Duplikat von Constructor in C, Initialisieren von C-Strukturen

    – aussen

    22. September 2010 um 23:28 Uhr


  • Keines der möglichen Duplikate (Standardkonstruktor in C oder Initialisieren von C-Strukturen in C++-Code) ist dafür wirklich ein gutes Duplikat, obwohl sie verwandt sind. Sie wurden umbenannt, seit der vorherige Kommentar abgegeben wurde.

    – Jonathan Leffler

    22. Dezember 2014 um 18:50 Uhr


Erstellen Sie in CI typischerweise eine Funktion im Stil eines Konstruktors, der dies tut. Zum Beispiel (Fehlerprüfung der Kürze halber weggelassen)

Object* Object_new(int id, int value) { 
  Object* p = malloc(sizeof(Object));
  p->id = id;
  p->value = value;
  return p;
}

...
Object* p1 = Object_new(id++, myValue);

  • Es mag ein bisschen übertrieben sein, aber ich erstelle normalerweise auch ein void objStruct_destroy(objStruct * obj), das für mich kostenlos ist, falls ich später eine Freigabe für zugewiesene Strukturen hinzufügen muss.

    – Mike Axiak

    22. September 2010 um 22:56 Uhr

  • Ja; außer dass es manchmal vorzuziehen ist, dass der “Konstruktor” stattdessen das Objekt * als Parameter verwendet, damit Sie auch eine Stapelzuweisung vornehmen können (Object object; Object_initialise(&object);).

    – Porculus

    22. September 2010 um 22:57 Uhr

  • Eine Zwischenmethode wäre ein Object_Init, um die Initialisierung eines bereits zugewiesenen Objekts (= Platzierungskonstruktor) durchzuführen, und ein Object_New, um es zuzuweisen und zu initieren (intern sollte es Object_Init aufrufen). Dasselbe sollte für den “Destruktor” gemacht werden.

    – Matteo Italien

    22. September 2010 um 23:01 Uhr

  • Aus der Sicht eines Anfängers: Gibt es einen Grund, warum Sie den Zeiger und nicht das Objekt/die Struktur selbst zurückgeben?

    – ALS EIN

    30. November 2014 um 18:51 Uhr

  • @Traubenfuchs, weil es bedeuten würde, bei der Rückgabe eine Kopie anzufertigen. Es könnte sein entflohenaber das ist nicht garantiert.

    – Ruslan

    5. Januar 2016 um 12:01 Uhr


Benutzeravatar von Jonathan Leffler
Jonathan Leffler

In C99 und höher können Sie ein zusammengesetztes Literal verwenden, das wie eine Umwandlung aussieht, gefolgt von einem Initialisierer in geschweiften Klammern:

int init_value = ...;
int init_id    = ...;
Object newObj1 = (Object){ .value = init_value, .id = init_id };
Object newObj2 = (Object){ .id = init_id, .value = init_value };

Die letzten beiden Zeilen erzielen den gleichen Effekt – die Reihenfolge der Felder ist nicht kritisch. Das ist die Verwendung von ‘designated initializers’, einer weiteren C99-Funktion. Sie können ein zusammengesetztes Literal erstellen, ohne bestimmte Initialisierer zu verwenden.

In C ist es möglich, eine Inline-Funktion mit demselben Namen wie eine Struktur zu deklarieren:

struct my
{
    int a;
};

inline struct my* my(int* a)
{
    return (struct my*)(a);
}

//somewhere in code
int num = 123;
struct my *sample = my(&num);
//somewhere in code

Es sieht C++ Ctors ziemlich ähnlich.

  • Wie funktioniert return (struct my*)(a) richten Sie die ein int a? Sollte es nicht von zugewiesen werden pointer_to_my->a?

    – VimNing

    17. Februar 2021 um 8:23 Uhr


  • Das ist nur eine Simulation von ctor: Die Adresse von num wird als Zeiger auf eine Struktur interpretiert, die aus einem Feld besteht – Integer. Dieser Trick funktioniert nicht, wenn man der Struktur ein weiteres Feld hinzufügt, z. B. Integer oder beispielsweise einen Zeiger: Die Übergabe der Adresse an die Funktion my() führt zu einem Datenmüll im zusätzlichen Feld.

    – grekhss

    18. Februar 2021 um 9:56 Uhr

  • ok, aber aus einer C-Datei bekomme ich Undefined symbol: _my; kein Fehler, wenn ich die entferne inline Stichwort

    – tontonCD

    12. Mai um 18:35 Uhr


struct thingy {
   char * label;
   int x;
};

#define declare_thingy( name, label, val) struct thingy name = { label, val }

struct thingy * new_thingy(const char * label, int val) {
     struct thingy * p = malloc(sizeof(struct thingy));
     if (p) {
          p->label = label;
          p->val = val;
     }
     return p;
}

Sie müssen wirklich die Initialisierung von unterscheiden static oder auto Variablen und dynamische Zuordnung auf dem Kopf. Führen Sie für den ersten benannte Initialisierer aus, für den zweiten eine gut spezifizierte Init-Funktion.

All das kann schön sein
in Makros verpackt mach es dir leicht static/auto Initialisierung und ähnliches new in C++.

Benutzeravatar von Tarantula
Tarantel

Wenn Sie nach einer objektorientierten “Emulation” über C suchen, empfehle ich dringend das GObject Type System [1]es ist ausgereift und wird beispielsweise von GTK weitgehend verwendet.

GLib [2] hat auch einen netten Slice-Zuordner für kleine Objekte, der derzeit von GNOME verwendet wird.

[1] GObject-Referenzhandbuch

[2] GLib-Speicherscheiben

1407450cookie-checkKonstruktor für Strukturen in C

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy