Assignez une structure à une autre en C

146

Pouvez-vous affecter une instance d'une structure à une autre, comme ceci:

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

Je l'ai vu fonctionner pour des structures simples, mais est-ce que cela fonctionne pour des structures complexes?
Comment le compilateur sait-il copier des éléments de données en fonction de leur type, c'est-à-dire en différenciant une intet une chaîne?

Shreyasva
la source

Réponses:

151

Oui si la structure est du même type. Pensez-y comme une copie mémoire.

fabrizioM
la source
72
Gardez à l'esprit qu'il n'y a pas de copie profonde, la mémoire n'est pas copiée.
Georg Schölly
3
La concurrence est également un problème ici.
Tim Post
16
@Tim Concurrency n'est pas plus un problème que pour l'affectation des types intégrés, comme les entiers et les doubles - l'affectation n'est pas non plus une opération atomique pour ces derniers.
2
OK, s'il y a une copie créée, puis-je libérer la mémoire plus tard avec free ()?
Betlista
5
@Betlista Vous ne pouvez pas libérer la mémoire avec free () car ce sont des variables automatiques: en.wikipedia.org/wiki/Automatic_variable
joshdoe
138

Oui, l'affectation est prise en charge pour les structures. Cependant, il y a des problèmes:

struct S {
   char * p;
};

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

Maintenant, les pointeurs des deux structures pointent vers le même bloc de mémoire - le compilateur ne copie pas les données pointées. Il est maintenant difficile de savoir quelle instance de struct possède les données. C'est pourquoi C ++ a inventé le concept d'opérateurs d'affectation définissables par l'utilisateur - vous pouvez écrire du code spécifique pour gérer ce cas.


la source
1
Je l'ai augmenté parce que la lecture m'a fait réaliser l'erreur / omission dans ma propre réponse.
Clifford
1
+1 pour avoir noté qu'il n'y a en fait aucune copie en cours.
Tom Duckering
14
Pourquoi cela a-t-il été signalé comme spam? Quelqu'un a-t-il perdu le contrôle de sa souris?
Georg Fritzsche
@gf Et apparemment aussi offensant!
2
@rahmanisback La réponse d'Anon est assez claire sur ce sujet: "le compilateur ne copie pas les données pointées ". Les données de structlui-même sont clairement copiées.
Tobias du
24

Regardez d'abord cet exemple:

Le code C pour un programme C simple est donné ci-dessous

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

Le code ASM équivalent pour foo_assign () est

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    

Comme vous pouvez voir qu'une affectation est simplement remplacée par une instruction "mov" dans l'assemblage, l'opérateur d'affectation signifie simplement déplacer des données d'un emplacement mémoire à un autre emplacement mémoire. L'affectation ne le fera que pour les membres immédiats d'une structure et échouera à la copie lorsque vous avez des types de données complexes dans une structure. Ici, COMPLEX signifie que vous ne pouvez pas avoir de tableau de pointeurs, pointant vers des listes.

Un tableau de caractères dans une structure ne fonctionnera pas lui-même sur la plupart des compilateurs, car l'affectation essaiera simplement de copier sans même regarder le type de données comme étant de type complexe.

Arun Kaushal
la source
2
Pouvez-vous préciser dans quelles conditions il échouerait car il semble fonctionner pour moi toujours
AlphaGoku
15

Ceci est une simple copie, comme vous le feriez avec memcpy()(en effet, certains compilateurs produisent en fait un appel à memcpy()pour ce code). Il n'y a pas de "chaîne" en C, seulement des pointeurs vers un groupe de caractères. Si votre structure source contient un tel pointeur, alors le pointeur est copié, pas les caractères eux-mêmes.

Thomas Pornin
la source
OK, donc le compilateur traduit cela en memcpy, voir ici: godbolt.org/z/nPxqWc - Mais maintenant, si je passe des pointeurs identiques aet b, et *a = *best traduit en un memcpycomportement indéfini, car pour memcpy"Les zones de mémoire ne doivent pas se chevaucher." (citant la page de manuel). Le compilateur a-t-il tort d'utiliser memcpyou ai-je tort d'écrire une telle affectation?
not-a-user le
6

Vouliez-vous dire "Complexe" comme un nombre complexe avec des parties réelles et imaginaires? Cela semble peu probable, donc sinon vous devrez donner un exemple puisque «complexe» ne signifie rien de spécifique en termes de langage C.

Vous obtiendrez une copie mémoire directe de la structure; si c'est ce que vous voulez dépend de la structure. Par exemple, si la structure contient un pointeur, les deux copies pointeront vers les mêmes données. Cela peut ou non être ce que vous voulez; cela dépend de la conception de votre programme.

Pour effectuer une copie «intelligente» (ou une copie «profonde»), vous devrez implémenter une fonction pour effectuer la copie. Cela peut être très difficile à réaliser si la structure elle-même contient des pointeurs et des structures qui contiennent également des pointeurs, et peut-être des pointeurs vers de telles structures (c'est peut-être ce que vous entendez par «complexe»), et c'est difficile à maintenir. La solution simple consiste à utiliser C ++ et à implémenter des constructeurs de copie et des opérateurs d'affectation pour chaque structure ou classe, puis chacun devient responsable de sa propre sémantique de copie, vous pouvez utiliser la syntaxe d'affectation et elle est plus facile à gérer.

Clifford
la source