memset () est-il plus efficace que pour la boucle en C?

Memset est plus efficace que pour la boucle. donc si j’ai

char x[500]; memset(x,0,sizeof(x)); 

ou

 char x[500]; for(int i = 0 ; i < 500 ; i ++) x[i] = 0; 

lequel est le plus efficace et pourquoi? Existe-t-il une instruction spéciale dans le matériel permettant d’initialiser le bloc?

Très certainement, memset sera beaucoup plus rapide que cette boucle. Notez comment vous traitez un caractère à la fois, mais ces fonctions sont tellement optimisées que vous définissez plusieurs octets à la fois, même en utilisant, le cas échéant, les instructions MMX et SSE.

Je pense que l’exemple paradigmatique de ces optimisations, qui passe généralement inaperçu, est la fonction strlen bibliothèque GNU C. On pourrait penser qu’il a au moins O (n) performances, mais qu’il a effectivement O (n / 4) ou O (n / 8) en fonction de l’architecture (oui, je sais, dans le grand O () sera le même , mais vous obtenez réellement un huitième du temps). Comment? Difficile, mais gentiment: strlen .

Pourquoi ne pas jeter un coup d’œil au code d’assemblage généré, optimisation complète sous VS 2010.

 char x[500]; char y[500]; int i; memset(x, 0, sizeof(x) ); 003A1014 push 1F4h 003A1019 lea eax,[ebp-1F8h] 003A101F push 0 003A1021 push eax 003A1022 call memset (3A1844h) 

Et ta boucle …

 char x[500]; char y[500]; int i; for( i = 0; i < 500; ++i ) { x[i] = 0; 00E81014 push 1F4h 00E81019 lea eax,[ebp-1F8h] 00E8101F push 0 00E81021 push eax 00E81022 call memset (0E81844h) /* note that this is *replacing* the loop, not being called once for each iteration. */ } 

Donc, sous ce compilateur, le code généré est exactement le même. memset est rapide et le compilateur est suffisamment intelligent pour savoir que vous appelez memset une fois de toute façon. Il le fait donc pour vous.

Si le compilateur a réellement laissé la boucle en l'état, il serait probablement plus lent, car vous pouvez définir plusieurs blocs de taille en octets à la fois (par exemple, vous pourriez dérouler votre boucle au moins. Vous pouvez supposer que memset sera au moins aussi rapidement qu'une implémentation naïve telle que la boucle. Essayez-la sous une version de débogage et vous remarquerez que la boucle n'est pas remplacée.

Cela dit, cela dépend de ce que le compilateur fait pour vous. Regarder le déassembly est toujours un bon moyen de savoir exactement ce qui se passe.

Cela dépend vraiment du compilateur et de la bibliothèque. Pour les compilateurs plus anciens ou simples, memset peut être implémenté dans une bibliothèque et ne fonctionnerait pas mieux qu’une boucle personnalisée.

Pour presque tous les compilateurs qui valent la peine d’être utilisés, memset est une fonction insortingnsèque et le compilateur générera un code en ligne optimisé.

D’autres ont suggéré de profiler et de comparer, mais cela ne me dérangerait pas. Il suffit d’utiliser memset. Le code est simple et facile à comprendre. Ne vous inquiétez pas jusqu’à ce que vos repères vous disent que cette partie du code est un point chaud de la performance.

La réponse est “ça dépend”. memset PEUT être plus efficace ou peut utiliser en interne une boucle for. Je ne peux pas penser à un cas où memset sera moins efficace. Dans ce cas, cela pourrait devenir une boucle for plus efficace: votre boucle itère 500 fois, en atsortingbuant à 0 la valeur d’un octet du tableau à chaque fois. Sur une machine 64 bits, vous pouvez effectuer une boucle en définissant 8 octets (une longue longue) à la fois, ce qui serait presque 8 fois plus rapide, et en ne traitant que les 4 octets restants (500% 8) à la fin.

MODIFIER:

En fait, memset ce que memset fait dans la glibc:

http://repo.or.cz/w/glibc.git/blob/HEAD:/ssortingng/memset.c

Comme Michael l’a souligné, dans certains cas (où la longueur du tableau est connue au moment de la compilation), le compilateur C peut insérer un memset ligne, memset la surcharge de l’appel de fonction. Glibc propose également des versions de memset optimisées pour l’assemblage sur la plupart des plates-formes majeures, telles que amd64:

http://repo.or.cz/w/glibc.git/blob/HEAD:/sysdeps/x86_64/memset.S

Les bons compilateurs reconnaîtront la boucle for et la remplaceront soit par une séquence en ligne optimale, soit par un appel à memset. Ils remplaceront également memset par une séquence en ligne optimale lorsque la taille de la mémoire tampon est petite.

En pratique, avec un compilateur optimiseur, le code généré (et donc les performances) sera identique.

D’accord avec ci-dessus. Ça dépend. Mais, bien sûr, memset est plus rapide ou égal à la boucle for. Si vous n’êtes pas sûr de votre environnement ou si vous êtes trop paresseux pour le tester, choisissez la route la plus sûre et utilisez memset.