Dans un cours de programmation système que j'ai suivi ce semestre précédent, nous avons dû implémenter un client / serveur de base en C.Lors de l'initialisation des structs, like sock_addr_in
, ou char buffers (que nous utilisions pour envoyer des données entre le client et le serveur) le professeur nous a demandé de les utiliser uniquement bzero
et de ne memset
pas les initialiser. Il n'a jamais expliqué pourquoi, et je suis curieux de savoir s'il y a une raison valable à cela?
Je vois ici: http://fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdown qui bzero
est plus efficace en raison du fait que la mémoire ne sera jamais remise à zéro, donc ce n'est pas doivent faire toute vérification supplémentaire qui memset
pourrait le faire. Cela ne semble pas nécessairement être une raison pour ne pas l'utiliser memset
pour la réinitialisation de la mémoire.
bzero
est considérée comme obsolète et n'est en outre pas une fonction C standard. Selon le manuel, il memset
est préférable bzero
pour cette raison. Alors, pourquoi voudriez-vous encore utiliser bzero
plus memset
? Juste pour les gains d'efficacité, ou est-ce quelque chose de plus? De même, quels sont les avantages de memset
sur bzero
qui en font l'option préférée de facto pour les programmes plus récents?
la source
memset
peut être légèrement moins efficace en raison de "un peu plus de vérification" est certainement un cas d'optimisation prématurée: quels que soient les gains que vous pourriez voir en omettant une instruction CPU ou deux ne valent pas la peine lorsque vous pouvez compromettre la portabilité de votre code.bzero
est obsolète, et c'est une raison suffisante pour ne pas l'utiliser.Réponses:
Je ne vois aucune raison de préférer
bzero
plusmemset
.memset
est une fonction C standard alors qu'ellebzero
n'a jamais été une fonction standard C. La raison est probablement que vous pouvez obtenir exactement la même fonctionnalité en utilisant lamemset
fonction.En ce qui concerne maintenant l'efficacité, les compilateurs comme
gcc
utilisent des implémentations intégrées pourmemset
lesquelles basculent vers une implémentation particulière lorsqu'une constante0
est détectée. Idemglibc
lorsque les fonctions intégrées sont désactivées.la source
memset
devrait toujours être utilisé dans ce cas, mais je ne savais pas pourquoi nous ne l'utilisions pas. Merci d'avoir clarifié et réaffirmé mes pensées.bzero
implémentations cassées . Sur les tableaux non alignés, il dépassait la longueur fournie et mettait à zéro un peu plus d'octets. Jamais eu un tel problème après le passage àmemset
.memset_s
ce qui doit être utilisé si vous voulez vous assurer que le compilateur n'optimise pas silencieusement un appel à «nettoyer» la mémoire à des fins liées à la sécurité (comme la suppression d'une région de mémoire contenant un une information comme un mot de passe en clair).Je suppose que vous avez utilisé (ou que votre professeur a été influencé par) la programmation réseau UNIX de W. Richard Stevens. Il utilise
bzero
fréquemment à la place dememset
, même dans l'édition la plus récente. Le livre est si populaire, je pense que c'est devenu un idiome dans la programmation réseau, c'est pourquoi vous le voyez toujours utilisé.Je m'en tiendrai
memset
simplement parce qu'ilbzero
est obsolète et réduit la portabilité. Je doute que vous voyiez des gains réels à utiliser l'un par rapport à l'autre.la source
Le seul avantage que je pense
bzero()
avoir sur lamemset()
mise à zéro de la mémoire est qu'il y a un risque réduit d'erreur.Plus d'une fois, j'ai rencontré un bug qui ressemblait à:
Le compilateur ne se plaindra pas (bien que peut-être augmenter certains niveaux d'avertissement sur certains compilateurs) et l'effet sera que la mémoire n'est pas effacée. Parce que cela ne détruit pas l'objet - cela le laisse tranquille - il y a de bonnes chances que le bogue ne se manifeste pas en quoi que ce soit d'évident.
Le fait que ce
bzero()
ne soit pas standard est un irritant mineur. (FWIW, je ne serais pas surpris si la plupart des appels de fonction dans mes programmes ne sont pas standard; en fait, écrire de telles fonctions est un peu mon travail).Dans un commentaire à une autre réponse ici, Aaron Newton a cité ce qui suit de Unix Network Programming, Volume 1, 3rd Edition par Stevens, et al., Section 1.2 (italiques ajoutés):
Je pense également que la grande majorité des appels à
memset()
sont à zéro mémoire, alors pourquoi ne pas utiliser une API adaptée à ce cas d'utilisation?Un inconvénient possible
bzero()
est que les compilateurs pourraient être plus susceptibles d'optimisermemcpy()
parce que c'est standard et qu'ils pourraient donc être écrits pour le reconnaître. Cependant, gardez à l'esprit qu'un code correct est toujours meilleur qu'un code incorrect optimisé. Dans la plupart des cas, l'utilisationbzero()
n'entraînera pas un impact notable sur les performances de votre programme, et celabzero()
peut être une macro ou une fonction en ligne qui se développe enmemcpy()
.la source
memset()
appels consistent simplement à supprimer un bloc de mémoire, ce qui, je pense, est un autre argument pourbzero()
. Que signifie le «b»bzero()
de toute façon?memset
viole un ordre de paramètre commun de "buffer, buffer_size" le rend particulièrement sujet aux erreurs.Je voulais parler de l'argument bzero vs memset. Installez ltrace puis comparez ce qu'il fait sous le capot. Sous Linux avec libc6 (2.19-0ubuntu6.6), les appels effectués sont exactement les mêmes (via
ltrace ./test123
):On m'a dit qu'à moins de travailler dans les entrailles profondes de la libc ou de n'importe quel nombre d'interfaces noyau / syscall, je n'ai pas à m'inquiéter pour eux. Tout ce dont je dois m'inquiéter, c'est que l'appel satisfasse à l'exigence de remise à zéro du tampon. D'autres ont mentionné lequel est préférable à l'autre, je vais donc m'arrêter ici.
la source
memset(ptr, 0, n)
quand elles voientbzero(ptr, n)
et qu'elles ne peuvent pas le convertir en code en ligne.extern void bzero(void *, size_t); void clear(void *p, size_t n) { bzero(p, n); }
produit un appel àmemset
. (Inclurestddef.h
poursize_t
sans rien d'autre qui pourrait interférer.)Vous ne devriez probablement pas utiliser
bzero
, ce n'est pas vraiment du C standard, c'était une chose POSIX.Et notez que le mot «était» - il était obsolète dans POSIX.1-2001 et supprimé dans POSIX.1-2008 par respect pour memset, il est donc préférable d'utiliser la fonction C standard.
la source
bzero
n'en fait pas partie.Pour la fonction memset, le deuxième argument est an
int
et le troisième argument estsize_t
,qui est typiquement un
unsigned int
, mais si les valeurs comme,0 and 16
pour le deuxième et le troisième argument respectivement sont entrées dans le mauvais ordre comme 16 et 0 alors, un tel appel à memset peut toujours fonctionner, mais ne fera rien. Parce que le nombre d'octets à initialiser est spécifié comme0
.Une telle erreur peut être évitée en utilisant bzero, car la permutation des deux arguments en bzero sera toujours interceptée par le compilateur C si des prototypes de fonction sont utilisés.
la source
En bref:
memset
nécessitent alors plus d'opérations d'assemblagebzero
.Voici la source: http://fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdown
la source
Ayez-le comme vous le souhaitez. :-)
Notez que:
bzero
ne renvoie rien,memset
retourne le pointeur void (d
). Cela peut être résolu en ajoutant le transtypage à void dans la définition.#ifndef bzero
ne vous empêche pas de masquer la fonction d'origine même si elle existe. Il teste l'existence d'une macro. Cela peut causer beaucoup de confusion.bzero
via des pointeurs de fonction, cela ne fonctionnera pas.la source
bzero
via des pointeurs de fonction, cela ne fonctionnera pas.bzero
. C'est une atrocité.memset prend 3 paramètres, bzero prend 2 en mémoire contraint ce paramètre supplémentaire prendrait 4 octets de plus et la plupart du temps, il sera utilisé pour tout mettre à 0
la source