164 votes

Affecter une structure à une autre dans C

Peut-on assigner une instance d'une structure à une autre, comme ceci :

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

J'ai vu que cela fonctionne pour des structures simples, mais est-ce que cela fonctionne pour des structures complexes ?
Comment le compilateur sait-il copier les éléments de données en fonction de leur type, c'est-à-dire en faisant la différence entre une int et de la ficelle ?

171voto

fabrizioM Points 11498

Oui, si la structure est du même type. Considérez-le comme une copie de la mémoire.

80 votes

Gardez à l'esprit qu'il n'y a pas de copie profonde, la mémoire pointée n'est pas copiée.

3 votes

La concurence est également un problème ici.

22 votes

@Tim La simultanéité 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 une opération atomique pour ces types non plus.

154voto

Oui, l'affectation est supportée pour les structs. 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 structs 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 structure possède les données. C'est pourquoi le C++ a inventé le concept d'opérateurs d'affectation définissables par l'utilisateur - vous pouvez écrire un code spécifique pour gérer ce cas.

2 votes

Je l'ai augmenté car en le lisant, je me suis rendu compte de l'erreur/omission dans ma propre réponse.

1 votes

+1 pour avoir noté qu'il n'y a pas réellement de copie en cours.

18 votes

Pourquoi ce message a-t-il été signalé comme un spam ? Quelqu'un a-t-il perdu le contrôle de sa souris ?

32voto

Arun Kaushal Points 61

Regardez d'abord cet exemple :

Le code C d'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 le suivant

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 le constater, une affectation est simplement remplacée par une instruction "mov" en assembleur. L'opérateur d'affectation signifie simplement déplacer des données d'un emplacement mémoire à un autre emplacement mémoire. L'assignation ne le fera que pour les membres immédiats d'une structure et échouera à copier lorsque vous avez des types de données complexes dans une structure. Ici, COMPLEXE 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 sur la plupart des compilateurs, car l'affectation essaiera simplement de copier sans même regarder le type de données pour être de type complexe.

2 votes

Pouvez-vous préciser dans quelles conditions cela échouerait, car cela semble toujours fonctionner pour moi.

0 votes

Augmenté pour la seule raison que cette réponse est incroyablement éducative. Merci !

19voto

Thomas Pornin Points 36984

Il s'agit d'une simple copie, comme vous le feriez avec memcpy() (en fait, certains compilateurs produisent 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.

2 votes

OK, donc le compilateur traduit ceci en memcpy voir ici : godbolt.org/z/nPxqWc - Mais maintenant, si je passe des pointeurs identiques a y b y *a = *b est traduit en un memcpy c'est un comportement indéfini, car pour memcpy " Les zones de mémoire ne doivent pas se chevaucher. " (citation de la page de manuel). Le compilateur a-t-il donc tort d'utiliser memcpy ou ai-je tort d'écrire une telle mission ?

7voto

Clifford Points 29933

Voulez-vous dire "complexe" comme dans un nombre complexe avec des parties réelles et imaginaires ? Cela semble peu probable, donc si ce n'est pas le cas, vous devez donner un exemple puisque "complexe" ne signifie rien de spécifique en termes de langage C.

Vous obtiendrez une copie en mémoire directe de la structure ; le fait que ce soit 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 être ou ne pas ê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 ces structures (c'est peut-être ce que vous entendez par "complexe"), et c'est difficile à maintenir. La solution simple est d'utiliser C++ et d'implémenter des constructeurs de copie et des opérateurs d'assignation pour chaque structure ou classe, alors chacune devient responsable de sa propre sémantique de copie, vous pouvez utiliser la syntaxe d'assignation, et c'est plus facile à maintenir.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X