Assegna una struttura all'altra in C


146

Puoi assegnare un'istanza di una struttura a un'altra, in questo modo:

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

L'ho visto funzionare per strutture semplici, ma funziona per strutture complesse?
Come fa il compilatore a sapere come copiare gli elementi di dati in base al loro tipo, cioè differenziando tra an inte stringa?

Risposte:


151

Sì se la struttura è dello stesso tipo. Pensalo come una copia di memoria.


72
Tieni presente che non esiste una copia approfondita, che indica che la memoria non viene copiata.
Georg Schölly,

3
Anche la concorrenza è un problema qui.
Tim Post

16
La concorrenza di @Tim non è più un problema di quanto non lo sia per l'assegnazione dei tipi incorporati, come numeri interi e doppi - l'assegnazione non è nemmeno un'operazione atomica per questi.

2
OK, se è stata creata una copia, posso liberare la memoria in seguito con free ()?
Betlista,

5
@Betlista Non puoi liberare la memoria con free () perché sono variabili automatiche: en.wikipedia.org/wiki/Automatic_variable
joshdoe

138

Sì, l'assegnazione è supportata per le strutture. Tuttavia, ci sono problemi:

struct S {
   char * p;
};

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

Ora i puntatori di entrambe le strutture puntano allo stesso blocco di memoria: il compilatore non copia i dati puntati. Ora è difficile sapere quale istanza di struttura possiede i dati. Questo è il motivo per cui C ++ ha inventato il concetto di operatori di assegnazione definibili dall'utente: è possibile scrivere un codice specifico per gestire questo caso.


1
L'ho aumentato perché leggendolo mi sono reso conto dell'errore / omissione nella mia risposta.
Clifford,

1
+1 per aver notato che in realtà non è in corso alcuna copia.
Tom Duckering,

14
Perché questo è stato contrassegnato come spam? Qualcuno ha perso il controllo del proprio mouse?
Georg Fritzsche,

@gf E apparentemente anche offensivo!

2
@rahmanisback La risposta di anon è abbastanza chiara su questo argomento: "il compilatore non copia i dati puntati ". I dati dello structstesso sono chiaramente copiati.
Tobias,

24

Primo sguardo a questo esempio:

Di seguito è riportato il codice C per un semplice programma C.

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;
}

Il codice ASM equivalente per foo_assign () è

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    

Come puoi vedere che un compito è semplicemente sostituito da un'istruzione "mov" in assembly, l'operatore di compito significa semplicemente spostare i dati da una posizione di memoria a un'altra posizione di memoria. L'assegnazione lo farà solo per i membri immediati di una struttura e non riuscirà a copiare quando si hanno tipi di dati complessi in una struttura. In questo caso, COMPLESSO significa che non è possibile disporre di array di puntatori, che puntano a elenchi.

Una matrice di caratteri all'interno di una struttura non funzionerà da sola sulla maggior parte dei compilatori, questo perché l'assegnazione tenterà semplicemente di copiare senza nemmeno guardare il tipo di dati per essere di tipo complesso.


2
Puoi capire a quali condizioni fallirebbe perché sembra funzionare sempre per me
AlphaGoku

15

Questa è una copia semplice, proprio come faresti con te memcpy()(in effetti, alcuni compilatori in realtà producono una chiamata memcpy()per quel codice). Non c'è "stringa" in C, solo puntatori a un gruppo di caratteri. Se la struttura di origine contiene un tale puntatore, il puntatore viene copiato, non i caratteri stessi.


OK, in modo che il compilatore traduce questo per memcpy, vedere qui: godbolt.org/z/nPxqWc - Ma ora, se mi passa i puntatori identici ae b, ed *a = *bè tradotto in una memcpyche è un comportamento indefinito, perché per memcpy"Le aree di memoria non devono sovrapporsi." (citando dalla pagina man). Quindi il compilatore ha torto nell'usare memcpyo sbaglio nello scrivere un tale compito?
non utente

6

Intendevi "complesso" come in numero complesso con parti reali e immaginarie? Questo sembra improbabile, quindi se non dovessi dare un esempio dato che "complesso" non significa nulla di specifico in termini di linguaggio C.

Otterrai una copia diretta della memoria della struttura; se questo è ciò che vuoi dipende dalla struttura. Ad esempio se la struttura contiene un puntatore, entrambe le copie punteranno agli stessi dati. Questo può essere o meno quello che vuoi; questo dipende dalla progettazione del programma.

Per eseguire una copia "intelligente" (o una copia "approfondita"), è necessario implementare una funzione per eseguire la copia. Questo può essere molto difficile da ottenere se la struttura stessa contiene puntatori e strutture che contengono anche puntatori e forse puntatori a tali strutture (forse è quello che intendi per "complesso"), ed è difficile da mantenere. La soluzione semplice è utilizzare C ++ e implementare i costruttori di copie e gli operatori di assegnazione per ciascuna struttura o classe, quindi ognuno diventa responsabile della propria semantica di copia, è possibile utilizzare la sintassi di assegnazione ed è più facilmente gestibile.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.