2015-11-14 7 views
1

je travaillais avec C et la gestion de la mémoire manuelle et jouer avec mon code et je remarquai ceci:Est-ce que memcpy doit toujours être utilisé?

Supposons que j'avais

int *a = malloc(sizeof(int)); 
int *b = malloc(sizeof(int)); 
int c = 10; 

Si je prends ces chiffres et faire ceci:

*a = c; 

Puis a pointera vers un emplacement distinct dans la mémoire distincte de c mais aura la valeur de c. Si j'ai utilisé:

memcpy(a, &c, sizeof(int)); 

La même chose se produirait. Pointeur distinct, même valeur.

Ma question est de savoir si l'un est préférable à l'autre? Je sais pour char * habituellement c'est memcpy ou strcpy qui est utilisé mais qu'en est-il pour ints? Qu'en est-il des pointeurs en général? La tâche est-elle toujours correcte?

P.S. Je sais aussi que

a = &c; 

fera le point a au même emplacement mémoire que c et ont donc sa valeur mais j'imagine que laisserait un pointeur suspendu où a était depuis free est jamais fait appel à la mémoire pour a donc je ne l'utiliserais pas.

+3

Vous ne recevez aucune surcharge d'appel de fonction pour '* a = c;' –

+3

'memcpy' est généralement utilisé uniquement lorsque vous ne pouvez pas effectuer une affectation normale, telle que la copie de tableaux. – Barmar

Répondre

2

Il est spécifique à la mise en œuvre. Certains compilateurs, y compris GCC, peuvent très bien optimiser (avec gcc -O2 au moins), les appels aux fonctions standard memcpy et memset (qui, comme l'a commenté mon ancien collègue Pascal Cuoq, peuvent être alignés sur un code machine d'affectation efficace); parfois, GCC est même capable d'optimiser certaines affectations à certaines structures comme des appels à memcpy (parfois, appeler une routine memcpy efficace est plus rapide pour suffisamment grand struct, y compris pour l'affectation de structure; à d'autres occasions, l'appel à memcpy, transformé via certains __builtin_memcpy , est inline comme un code d'affectation efficace, peut-être même aller à travers les registres sans utiliser la mémoire)

vous pouvez compiler votre foo.c exemple avec gcc -fverbose-asm -O2 -march=native -S foo.c puis regardez dans le produit foo.s

donc, si vous utilisez un récentcompilateurou Clang/LLVM (ou d'un autre bon compilateur) avec optimisations ont permis, vous devez utiliser memcpy et memset ...

En d'autres termes, memcpy(a, &c, sizeof(int)); peuvent être optimisés de manière aussi efficace que *a = c; (et si vous définissez une macro "type générique" en utilisant _Generic de C99, vous utiliseriez memcpy et il devrait être optimisé efficacement).

+1

Et vice versa, un appel comme 'memcpy (a, & c, sizeof (int)); 'est susceptible d'être optimisé pour un couple d'instructions qui semblent avoir été générées à partir de' * a = c; '. –

+1

Voulez-vous dire qu'ils optimisent 'memcpy' ** mieux ** qu'une simple affectation? Si le code optimisé est équivalent, pourquoi recommandez-vous qu'ils "utilisent memcpy"? – Barmar

+0

Vous utiliserez 'memcpy' dans le cas générique, etc ... –

4

Dans votre exemple, vous devez utiliser *a = c; car vous ne voulez copier qu'une seule valeur. Utilisez memcpy si vous devez copier plusieurs éléments consécutifs d'un tableau.

0

La memcpy doit-elle toujours être utilisée?

Ordinaire et simple, no.

Votre premier but en écrivant du code est de le rendre compréhensible et maintenable. Tout le monde sait ce que *a = c va faire quand a est déclaré comme un pointeur sur un int et c est déclaré comme un int. Le compilateur sait également exactement ce que vous entendez par là. Vous ne verrez jamais un compilateur optimiser votre *a = c à un appel à memcpy parce que ce serait une désoptimisation.

Vous verrez le compilateur optimisez *a=c à un appel à memcpy lorsque c est de type struct AVeryLargeStruct et a est un pointeur sur la même chose. Il n'y a pas besoin de convertir *a=c en memcpy(a,&c, sizeof(c)) parce que le compilateur fait cela pour vous, un gratis. Ecrire *a=c parce que c'est plus clair et moins sujet aux erreurs que le memcpy.

Il y a quelques endroits où vous ne vraiment besoin d'utiliser memcpy (ou memmove):

  • copie d'un tableau,
  • type calembour, sans utiliser les syndicats et
  • copie ou de mémoire mal alignée.

La première est la procédure opératoire standard; Personne ne sera choqué en lisant votre code et en voyant un appel à memcpy lorsqu'il est utilisé dans ce contexte. Les deux derniers ne sont pas SOP. Dans ce contexte, les utilisations de memcpy donneront une pause aux lecteurs de votre code. C'est une bonne chose parce que vous faites quelque chose d'un peu délicat là-bas. Cacher ces appels difficiles à memcpy parmi des milliers d'autres appels à memcpy où vous auriez pu utiliser l'affectation ordinaire rend ces quelques endroits où vous devez absolument utiliser memcpy ne pas se démarquer. C'est une bonne chose que si votre objectif est de gagner l'IOCCC.

Si vous utilisez memcpy partout où vous êtes susceptible de rendre votre code plus lent et vous êtes encore plus susceptible de faire croire aux autres que quelque chose ne va pas avec votre code.