Weisen Sie in C eine Struktur einer anderen zu

146

Können Sie eine Instanz einer Struktur einer anderen zuweisen, wie folgt:

struct Test t1;
struct Test t2;
t2 = t1;

Ich habe gesehen, dass es für einfache Strukturen funktioniert, aber funktioniert es für komplexe Strukturen?
Woher weiß der Compiler, wie Datenelemente abhängig von ihrem Typ kopiert werden, dh zwischen einem intund einem String zu unterscheiden?

Shreyasva
quelle

Antworten:

151

Ja, wenn die Struktur vom gleichen Typ ist. Denken Sie es als Speicherkopie.

fabrizioM
quelle
72
Denken Sie daran, dass es keine tiefe Kopie gibt, die auf den Speicher zeigt und nicht kopiert wird.
Georg Schölly
3
Parallelität ist auch hier ein Problem.
Tim Post
16
@ Tim Concurrency ist nicht mehr ein Problem als die Zuweisung der eingebauten Typen wie Ganzzahlen und Doppel - die Zuweisung ist auch für diese keine atomare Operation.
2
OK, wenn eine Kopie erstellt wurde, kann ich den Speicher später mit free () freigeben?
Betlista
5
@ Betlista Sie können den Speicher nicht mit free ()
freigeben,
138

Ja, die Zuweisung wird für Strukturen unterstützt. Es gibt jedoch Probleme:

struct S {
   char * p;
};

struct S s1, s2;
s1.p = malloc(100);
s2 = s1;

Jetzt zeigen die Zeiger beider Strukturen auf denselben Speicherblock - der Compiler kopiert nicht die Daten, auf die verwiesen wird. Es ist jetzt schwierig zu wissen, welcher Strukturinstanz die Daten gehören. Aus diesem Grund hat C ++ das Konzept der benutzerdefinierbaren Zuweisungsoperatoren erfunden. Sie können spezifischen Code schreiben, um diesen Fall zu behandeln.


quelle
1
Ich habe es erhöht, weil ich durch das Lesen den Fehler / die Auslassung in meiner eigenen Antwort erkannt habe.
Clifford
1
+1 für die Feststellung, dass tatsächlich kein Kopieren stattfindet.
Tom Duckering
14
Warum wurde dies als Spam gekennzeichnet? Hat jemand die Kontrolle über seine Maus verloren?
Georg Fritzsche
@gf Und anscheinend auch so anstößig!
2
@rahmanisback Die Antwort von anon ist zu diesem Thema ziemlich klar: "Der Compiler kopiert nicht die Daten, auf die verwiesen wird ". Die Daten von sich structselbst werden klar kopiert.
Tobias
24

Schauen Sie sich zuerst dieses Beispiel an:

Der C-Code für ein einfaches C-Programm ist unten angegeben

struct Foo {
    char a;
    int b;
    double c;
    } foo1,foo2;

void foo_assign(void)
{
    foo1 = foo2;
}
int main(/*char *argv[],int argc*/)
{
    foo_assign();
return 0;
}

Der äquivalente ASM-Code für foo_assign () lautet

00401050 <_foo_assign>:
  401050:   55                      push   %ebp
  401051:   89 e5                   mov    %esp,%ebp
  401053:   a1 20 20 40 00          mov    0x402020,%eax
  401058:   a3 30 20 40 00          mov    %eax,0x402030
  40105d:   a1 24 20 40 00          mov    0x402024,%eax
  401062:   a3 34 20 40 00          mov    %eax,0x402034
  401067:   a1 28 20 40 00          mov    0x402028,%eax
  40106c:   a3 38 20 40 00          mov    %eax,0x402038
  401071:   a1 2c 20 40 00          mov    0x40202c,%eax
  401076:   a3 3c 20 40 00          mov    %eax,0x40203c
  40107b:   5d                      pop    %ebp
  40107c:   c3                      ret    

Wie Sie sehen können, wird eine Zuweisung in der Baugruppe einfach durch eine Anweisung "mov" ersetzt. Der Zuweisungsoperator bedeutet einfach, Daten von einem Speicherort an einen anderen Speicherort zu verschieben. Die Zuweisung wird nur für unmittelbare Mitglieder einer Struktur ausgeführt und kann nicht kopiert werden, wenn Sie komplexe Datentypen in einer Struktur haben. Hier bedeutet KOMPLEX, dass Sie kein Array von Zeigern haben können, die auf Listen zeigen.

Ein Array von Zeichen innerhalb einer Struktur funktioniert auf den meisten Compilern selbst nicht. Dies liegt daran, dass die Zuweisung einfach versucht, zu kopieren, ohne den Datentyp als komplex anzusehen.

Arun Kaushal
quelle
2
Können Sie
herausfinden, unter
15

Dies ist eine einfache Kopie, genau wie Sie es tun würden memcpy()(tatsächlich erzeugen einige Compiler tatsächlich einen Aufruf memcpy()für diesen Code). Es gibt keine "Zeichenfolge" in C, nur Zeiger auf eine Reihe von Zeichen. Wenn Ihre Quellstruktur einen solchen Zeiger enthält, wird der Zeiger kopiert, nicht die Zeichen selbst.

Thomas Pornin
quelle
OK, also übersetzt der Compiler dies in memcpy, siehe hier: godbolt.org/z/nPxqWc - Aber jetzt, wenn ich identische Zeiger übergebe aund bund *a = *bin ein memcpyundefiniertes Verhalten übersetzt wird, weil für memcpy"Die Speicherbereiche dürfen sich nicht überlappen." (zitiert aus der Manpage). Ist der Compiler also falsch in der Verwendung memcpyoder bin ich falsch darin, eine solche Aufgabe zu schreiben?
kein Benutzer
6

Meinten Sie "Komplex" wie in komplexer Zahl mit Real- und Imaginärteilen? Dies scheint unwahrscheinlich. Wenn nicht, müssten Sie ein Beispiel nennen, da "komplex" nichts Spezifisches in Bezug auf die C-Sprache bedeutet.

Sie erhalten eine direkte Speicherkopie der Struktur. ob Sie das wollen, hängt von der Struktur ab. Wenn die Struktur beispielsweise einen Zeiger enthält, zeigen beide Kopien auf dieselben Daten. Dies kann oder kann nicht sein, was Sie wollen; Das liegt an Ihrem Programmdesign.

Um eine "intelligente" Kopie (oder eine "tiefe" Kopie) durchzuführen, müssen Sie eine Funktion implementieren, um die Kopie auszuführen. Dies kann sehr schwierig zu erreichen sein, wenn die Struktur selbst Zeiger und Strukturen enthält, die auch Zeiger enthalten, und möglicherweise Zeiger auf solche Strukturen (vielleicht meinen Sie das mit "komplex"), und es ist schwer zu pflegen. Die einfache Lösung besteht darin, C ++ zu verwenden und Kopierkonstruktoren und Zuweisungsoperatoren für jede Struktur oder Klasse zu implementieren. Anschließend wird jede für ihre eigene Kopiersemantik verantwortlich. Sie können die Zuweisungssyntax verwenden und die Verwaltung ist einfacher.

Clifford
quelle