Struktur initialisieren / auf Null / Null zurücksetzen

91
struct x {
    char a[10];
    char b[20];
    int i;
    char *c;
    char *d[10];
};

Ich fülle diese Struktur und benutze dann die Werte. Bei der nächsten Iteration möchte ich alle Felder auf 0oder nullvor der Wiederverwendung zurücksetzen .

Wie kann ich das machen? Kann ich verwenden memsetoder muss ich alle Mitglieder durchgehen und es dann einzeln tun?

Hari
quelle

Antworten:

108

Definieren Sie eine konstante statische Instanz der Struktur mit den Anfangswerten und weisen Sie diesen Wert dann einfach Ihrer Variablen zu, wenn Sie ihn zurücksetzen möchten.

Beispielsweise:

static const struct x EmptyStruct;

Hier verlasse ich mich auf die statische Initialisierung , um meine Anfangswerte festzulegen, aber Sie können einen Strukturinitialisierer verwenden, wenn Sie andere Anfangswerte wünschen.

Dann können Sie jedes Mal um die Schleife schreiben:

myStructVariable = EmptyStruct;
David Heffernan
quelle
1
@ David Heffernan: Ist das besser als zu verwenden, memsetwenn ich nur alles zurücksetzen möchte 0?
Hari
9
@ Hari Ich würde diesen Ansatz lieber selbst. Wenn memsetich es benutze, fühle ich mich schmutzig. Ich ziehe es vor, den Compiler nach Möglichkeit um das Speicherlayout kümmern zu lassen. Genau genommen ist eine solche Verwendung memsetnicht portierbar, aber in der Praxis wäre ich erstaunt, wenn Sie Ihren Code jemals irgendwo kompilieren würden, wo es darauf ankommt. Sie können memset also wahrscheinlich sicher verwenden, wenn Sie es bevorzugen.
David Heffernan
2
@ Hari, es ist konzeptionell besser, da Sie einen Standard-Initialisierungswert (so etwas wie ein Objektfabrikmuster) angeben
Diego Sevilla
1
@cnicutar Ich weiß das. Beachten Sie, dass meine Antwort empfiehlt, kein Memset zu verwenden. Beachten Sie auch den Kommentar darüber, wo ich auf die Nichtportabilität der Verwendung von memset als Mittel zum Zuweisen von Nullwerten hinweise. Mein vorheriger Kommentar weist nur auf die Realität hin, dass 0 Bits immer Gleitkomma-Nullen entsprechen.
David Heffernan
1
@ kp11 Zitat bitte
David Heffernan
84

Wenn Sie ein modernes C (C99) haben, können Sie so etwas tun, indem Sie ein zusammengesetztes Literal verwenden .

a = (const struct x){ 0 };

Dies ist etwas ähnlich wie Davids Lösung, nur dass Sie sich keine Sorgen machen müssen, um eine leere Struktur zu deklarieren oder ob Sie sie deklarieren möchten static. Wenn Sie das constwie ich verwenden, kann der Compiler das zusammengesetzte Literal gegebenenfalls statisch im Nur-Lese-Speicher zuweisen.

Jens Gustedt
quelle
Erstellt das eine Instanz von x auf dem Stapel, um es dann auf a zu kopieren? Bei großen Strukturen / kleinen Stapeln könnte dies ein Problem sein.
Étienne
1
Wie alle Optimierungen ist dies vollständig vom Compiler abhängig, sodass Sie überprüfen müssen, was Ihr Compiler produziert. "Normalerweise" bei modernen Compilern ist dies nicht der Fall. Diese können Initialisierungen sehr gut verfolgen und nur das Notwendige tun, nicht mehr. (Und denken Sie nicht, dass solche Dinge Probleme sind, bevor Sie eine echte Verlangsamung messen. Sie sind normalerweise nicht.)
Jens Gustedt
3
Warnungen vor "fehlenden Initialisierern" sind wirklich falsch. Der C-Standard schreibt genau vor, was als geschehen muss, und sieht den { 0 }als Standardinitialisierer vor. Schalten Sie diese Warnung aus, es handelt sich um einen falschen Fehlalarm.
Jens Gustedt
1
@JensGustedt Wird diese Typisierung wirklich benötigt? Kann ich es nicht so schreiben? struct xa = (const) {0};
Patrick
1
@Patrick, obwohl die Syntax ähnlich ist, handelt es sich nicht um eine Besetzung, sondern um ein "zusammengesetztes Literal". Und Sie verwechseln Initialisierung und Zuweisung.
Jens Gustedt
57

Besser als alle oben genannten ist es, jemals die Standard C-Spezifikation für die Strukturinitialisierung zu verwenden:

struct StructType structVar = {0};

Hier sind alle Bits Null (je).

user411313
quelle
13
Ich glaube nicht, dass Sie das jedes Mal um eine Schleife tun können
David Heffernan
2
Dies soll in der Tat funktionieren. Aber leider beschweren sich gcc & g ++ darüber. gcc generiert Warnungen, während g ++ einen Fehler generiert. Ich weiß, dass gcc & g ++ daran schuld sind (sie sollen der Standard C-Spezifikation entsprechen), aber für eine gute Portabilität ist es dennoch zwingend erforderlich, eine solche Einschränkung zu berücksichtigen.
Cyan
3
@Cyan Sie können {}in C ++ verwenden. Die gcc-Entwickler scheinen sich nicht sicher zu sein, ob C ++ unterstützt werden soll,{0} und ich bin mit diesem Teil des Standards selbst nicht vertraut.
Matthew Read
@Matthew: Ja, eigentlich habe ich memset () verwendet, weil es zu viele Portabilitätsprobleme mit {0}oder gab {}. Ich bin mir nicht sicher, ob die C & C ++ - Standards in diesem Punkt klar und synchron sind, aber anscheinend sind Compiler dies nicht.
Cyan
Wird dies in einem solchen Fall funktionieren? struct StructType structVar = malloc (sizeof(StructType)); structVar ={0}
Sam Thomas
34

In C ist es eine gängige Redewendung, den Speicher für eine structVerwendung auf Null zu setzen memset:

struct x myStruct;
memset(&myStruct, 0, sizeof(myStruct));

Technisch gesehen glaube ich nicht, dass dies portabel ist, da davon ausgegangen wird, dass der NULLZeiger auf einem Computer durch den ganzzahligen Wert 0 dargestellt wird, aber er wird häufig verwendet, da dies auf den meisten Computern der Fall ist.

Wenn Sie von C nach C ++ wechseln, achten Sie darauf, diese Technik nicht bei jedem Objekt anzuwenden. C ++ macht dies nur für Objekte ohne Elementfunktionen und ohne Vererbung zulässig.

templatetypedef
quelle
2
Der C-Standard besagt, dass NULL immer 0 ist. Wenn die Maschine so ausgelegt ist, dass eine vorgegebene ungültige Adresse nicht buchstäblich 0 ist, muss der Compiler für diese Architektur während der Kompilierung angepasst werden.
Kevin M
8
@ KevinM Ja, das Symbol "0" entspricht immer dem NULL-Zeiger, auch wenn er nur Null ist. Der Compiler kann jedoch nichts tun, wenn Sie die Bits mit memset auf Null setzen.
Adrian Ratnapala
"C ++ macht dies nur für Objekte ohne Elementfunktionen und ohne Vererbung zulässig." Es geht darum, ob der Typ als "einfache alte Daten" betrachtet wird. Die Kriterien hängen von der Version der C ++ - Sprache ab.
Max Barraclough
19

Wenn Sie einen C99-kompatiblen Compiler haben, können Sie diesen verwenden

mystruct = (struct x){0};

Andernfalls sollten Sie das tun, was David Heffernan geschrieben hat, dh erklären:

struct x empty = {0};

Und auf dem Laufenden:

mystruct = empty;
Rudy Velthuis
quelle
6

Sie können memsetmit der Größe der Struktur verwenden:

struct x x_instance;
memset (&x_instance, 0, sizeof(x_instance));
Diego Sevilla
quelle
1
Ich denke nicht, dass die Besetzung hier notwendig ist. Ist es?
Templatetypedef
Nun, ich bin so an C ++ gewöhnt, dass ... nun, es wird auch in C ++ funktionieren, also sehe ich es nicht als Belastung an.
Diego Sevilla
Ja, ich war nicht spezifisch genug. Jeder Zeiger auf cv-qualifiziertes T kann in cv-qualifiziertes void * konvertiert werden. Jeder Datenzeiger, Funktionszeiger ist eine ganz andere Sache. Kudos @ Kevin
Marcus Borkenhagen
memsetist eine Option, aber wenn Sie sie verwenden, müssen Sie sicherstellen, dass der Speicher, in den geschrieben wird, genau die gleiche Größe wie der dritte Parameter hat. Deshalb ist es besser, sich auf die Größe des tatsächlichen Objekts zu beziehen, nicht auf die Größe des Typs, den Sie verwenden weiß es aktuell ist. IOW memset (&x_instance, 0, sizeof(x_instance));ist eine viel bessere Wahl. Übrigens: Die (void*)Besetzung ist auch in C ++ überflüssig.
Wolf
(Entschuldigung, ich habe mich nicht um die Frage
Wolf
5

Ich glaube, Sie können {}Ihrer Variablen einfach die leere Menge ( ) zuweisen .

struct x instance;

for(i = 0; i < n; i++) {
    instance = {};
    /* Do Calculations */
}
Archmede
quelle
0
 struct x myX;
 ...
 memset(&x, 0, sizeof(myX));
Josh Matthews
quelle
5
Ich denke, OP weiß, wie man Memset aufruft, aber die Frage ist, ob dies klug ist oder nicht
David Heffernan
-1

Bildbeschreibung hier eingeben Überraschen Sie gnu11!

typedef struct {
    uint8_t messType;
    uint8_t ax;  //axis
    uint32_t position;
    uint32_t velocity;
}TgotoData;

TgotoData tmpData = { 0 };

nichts ist null.

Андрей Тернити
quelle
1
Dies versucht nicht, die Frage "Wie kann ich alle Felder auf 0 zurücksetzen" zu beantworten
MM