56 votes

effacement d'un tableau de petit entier: memset vs. for for

Il y a deux façons de mettre à zéro un tableau entier / flottant:

 memset(array, 0, sizeof(int)*arraysize);
 

ou:

 for (int i=0; i <arraysize; ++i)
    array[i]=0;
 

évidemment, memset est plus rapide pour les grands arraysize . Cependant, à quel moment les frais généraux de memset sont-ils réellement supérieurs aux frais généraux de la boucle for? Par exemple, pour un tableau de taille 5, lequel serait le mieux? La première, la deuxième ou peut-être même la version non-laminée:

 array[0] = 0;
array[1] = 0;
array[2] = 0;
array[3] = 0;
array[4] = 0;
 

45voto

Michael Burr Points 181287

Selon toute vraisemblance, memset() est insérée par votre compilateur (la plupart des compilateurs de la traiter comme une 'intrinsèque', ce qui signifie qu'il est inline, sauf peut-être à la plus faible des optimisations ou moins explicitement désactivée).

Pour exemple, voici quelques notes de version de GCC 4.3:

La génération de Code de déplacer bloc (memcpy) et de l'ensemble de block (memset) a été réécrit. GCC pouvez maintenant choisir le meilleur algorithme (boucle, déroulé de la boucle, avec l'instruction rep préfixe ou un appel de la bibliothèque) se basant sur la taille de la bloquer la copie et le CPU étant optimisé pour. Une nouvelle option -minline-stringops-dynamicallya été ajouté. Avec cette option chaîne les opérations de taille inconnue sont élargi tels que les petits blocs sont copié par en de ligne de code, tandis que pour de gros blocs d'un appel de la bibliothèque est utilisée. C'est plus rapide que le code -minline-all-stringops lorsque le mise en œuvre de bibliothèque est capable de utilisation du cache de la hiérarchie des indices. L' heuristique de choix du particulier l'algorithme peut être remplacé par -mstringop-strategy. Nouvellement aussi memset des valeurs différentes de 0 est inline.

Il pourrait être possible pour le compilateur de faire quelque chose de similaire avec les autres exemples que vous citez, mais je serais prêt à parier qu'il est moins probable pour.

Et c'est grep-mesure et plus immédiatement évident au regard de ce que l'intention est de démarrer (pas que la boucle est particulièrement difficile à analyser).

21voto

bdijkstra Points 159

Comme Michael l’a déjà noté, gcc et la plupart des autres compilateurs l’optimisent déjà très bien. Par exemple, gcc tourne ceci

 char arr[5];
memset(arr, 0, sizeof arr);
 

dans

 movl  $0x0, <arr+0x0>
movb  $0x0, <arr+0x4>
 

Ça ne vaut pas mieux que ça ...

8voto

Roddy Points 32503

Il n'y a aucun moyen de répondre à la question sans la mesurer. Il va entièrement dépendre du compilateur, de l'uc et de la bibliothèque d'exécution des implémentations.

memset() peut être peu un "code d'odeur", parce qu'elle peut être sujette à des dépassements de la mémoire tampon, le paramètre reprises et a la fâcheuse capacité de seulement compensation 'octet-sage". Cependant, il y a fort à parier que ce sera le plus rapide', mais dans tous les cas extrêmes.

J'ai tendance à utiliser une macro pour envelopper ceci afin d'éviter certains des problèmes:

#define CLEAR(s) memset(&(s), 0, sizeof(s))

Cette laisse de côté les calculs de la taille et supprime le problème de permutation de la longueur et de la vlaue paramètres.

En bref, utiliser memset() "sous le capot". Écrire ce que vous souhaitez, et laisser le compilateur s'inquiéter des optimisations. La plupart sont incroyablement bon.

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