Por que usar bzero sobre memset?

Em uma Programação de Sistemas, classe I tomou este semestre anterior, tivemos que implementar uma base de cliente/servidor em C. Quando inicializar as estruturas, como sock_addr_in, ou char buffers (que usamos para enviar dados e para trás entre o cliente e o servidor), o professor ensinou-nos a usar apenas bzero e não memset para inicializá-los. Ele nunca explicou porquê, e estou curioso se há uma razão válida para isto?

Estou a ver aqui.: http://fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdown isso bzero é mais eficiente devido ao facto de que só vai estar a zerar a memória, por isso não tem de fazer nenhuma verificação adicional que memset possa fazer. Isso ainda não parece necessariamente uma razão para absolutamente não usar memset para zerar a memória.

bzero é considerada obsoleta e, além disso, não é uma função C padrão. De acordo com o manual, memset é preferível a bzero para isto. razao. Então porque é que ainda queres usar bzero em memset? Só pelos ganhos de eficiência, ou é algo mais? Da mesma forma, Quais são os benefícios de memset sobre bzero que o tornam a opção de facto preferida para programas mais recentes?

Author: PseudoPsyche, 2013-06-14

8 answers

Não vejo razão para preferir {[[0]} mais memset.

memset é uma função C padrão enquanto bzero nunca foi uma função C padrão. A lógica é provavelmente porque você pode alcançar exatamente a mesma funcionalidade usando a função memset.

Agora em relação à eficiência, compiladores como gcc usam implementações de builtin para {[1] } que mudam para uma implementação particular quando uma constante 0 é detectada. O mesmo para glibc quando as compilações estão desactivadas.

 133
Author: ouah, 2013-06-13 21:06:22
Acho que usaste (ou o teu professor foi influenciado por) programação de rede UNIX por W. Richard Stevens. Ele usa {[[0]} frequentemente em vez de memset, mesmo na edição mais atualizada. O livro é tão popular, que eu acho que se tornou um idioma na programação de rede e é por isso que você ainda o vê usado.

Eu ficaria com memset simplesmente porque {[[0]} está desactualizado e reduz a portabilidade. Duvido que vejas algum ganho real em usar um em vez do outro.

 58
Author: austin, 2013-06-13 21:05:12
A única vantagem que eu acho que bzero() tem sobre memset() para ajustar a memória a zero é que há uma possibilidade reduzida de um erro ser cometido. Mais de uma vez deparei-me com um insecto que parecia ...
memset(someobject, size_of_object, 0);    // clear object

O compilador não vai reclamar (embora talvez aumentando alguns níveis de aviso pode em alguns compiladores) e o efeito será que a memória não é limpa. Porque isto não destrói o objecto-deixa-o em paz-há uma boa hipótese de que o insecto pode não se manifestar em nada óbvio.

O facto de bzero() não ser o padrão é um pouco irritante. (FWIW, eu não ficaria surpreso se a maioria das chamadas de função em meus programas não são padrão; na verdade, escrever tais funções é tipo o meu trabalho).

Em um comentário para outra resposta aqui, Aaron Newton citou o seguinte da programação de rede Unix, Volume 1, 3rd Edition por Stevens, et al., Ponto 1.2 (sublinhado nosso):

bzero não é uma função ANSI C. É derivado do Berkely precoce código de rede. No entanto, utilizamo-lo em todo o texto, em vez disso da função ANSI C memset, porque bzero é mais fácil de lembrar (com apenas dois argumentos) do que memset (com três argumentos). Quase cada fornecedor que suporta a API sockets também fornece bzero, e se não, nós fornecemos uma macro definição no nosso cabeçalho unp.h.

De facto, o autor do TCPv3 [TCP / IP Illustrated, Volume 3-Stevens 1996] cometeu o erro de trocar o segundo e terceiro argumento para memset em 10 ocorrências na primeira impressão . Um compilador C não consegue apanhar este erro porque ambos os argumentos são do mesmo tipo. (Na verdade, o segundo argumento é um int e o terceiro argumento é size_t, que é tipicamente um unsigned int, mas os valores especificados, 0 e 16, respectivamente, ainda são aceitáveis para o outro tipo de argumento.) A chamada para {[5] } ainda funcionou, porque apenas algumas das funções do 'socket' requerem que o os últimos 8 bytes de uma estrutura de endereços de socket de Internet são definidos como 0. No entanto, foi um erro, que poderia ser evitado usando bzero, porque trocar os dois argumentos para bzero será sempre capturada pelo compilador C se forem utilizados protótipos de função.

Eu também acredito que a grande maioria das chamadas para {[[2]} são para memória zero, então porque não usar uma API que é adaptada para esse caso de uso?

Uma possível desvantagem para bzero() é que os compiladores podem ser mais provavelmente para otimizar memcpy() porque é padrão e então eles podem ser escritos para reconhecê-lo. No entanto, tenha em mente que o código correto ainda é melhor do que o código incorreto que foi otimizado. Na maioria dos casos, o uso de bzero() não irá causar um impacto notável no desempenho do seu programa, e que bzero() pode ser uma função macro ou inline que se expande para memcpy().

 41
Author: Michael Burr, 2015-09-12 01:05:16

Em resumo: memset necessita de mais operações de montagem do que bzero.

Esta é a fonte: http://fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdown

 5
Author: Tal Bar, 2014-01-16 09:07:19
{[[2]} você provavelmente não deveria {[[4]} Usar {[[0]}, não é realmente o padrão C, era uma coisa POSIX.

E note que a palavra " foi " - foi depreciado em POSIX.1-2001 e removido em POSIX.1-2008 em deferência ao memset para que esteja melhor usando a função C padrão.

 3
Author: paxdiablo, 2015-04-28 22:28:07
Queria falar sobre o argumento do bzero vs. memset. Instale o iTrace e depois compare o que ele faz sob o capô. Em Linux com libc6( 2.19-0ubuntu6. 6), As chamadas feitas são exatamente as mesmas (via ltrace ./test123):
long m[] = {0}; // generates a call to memset(0x7fffefa28238, '\0', 8)
int* p;
bzero(&p, 4);   // generates a call to memset(0x7fffefa28230, '\0', 4)

Disseram-me que a menos que esteja a trabalhar nas profundezas da libc ou em qualquer número de interface kernel/syscall, Não tenho de me preocupar com eles. A única coisa com que me devo preocupar é que a chamada satisfaça a exigência de zero no buffer. Outros têm mencionado sobre qual deles é melhor do que o outro, então vou parar aqui.

 2
Author: gumchew, 2015-04-22 14:32:16

Para a função memset, o segundo argumento é um int e o terceiro argumento é size_t,

void *memset(void *s, int c, size_t n);

Que é tipicamente um unsigned int, mas se os valores como, 0 and 16 para o segundo e terceiro argumentos respectivamente são inseridos na ordem errada como 16 e 0 então, tal chamada para memset ainda pode funcionar, mas não fará nada. Porque o número de bytes a inicializar são especificados como 0.

void bzero(void *s, size_t n)

Tal erro pode ser evitado usando bzero, porque trocar os dois argumentos para bzero será sempre apanhado pelo compilador C se forem utilizados protótipos de função.

 1
Author: havish, 2013-12-23 06:29:20
Faz como quiseres. :-)
#ifndef bzero
#define bzero(d,n) memset((d),0,(n))
#endif

Note que:

  1. o bzero original não devolve nada, memset devolve o cursor vazio (d). Isto pode ser corrigido adicionando o typecast ao vazio na definição.
  2. #ifndef bzero não o impede de esconder a função original mesmo que ela exista. Testa a existência de uma macro. Isto pode causar muita confusão.
  3. É impossível criar um ponteiro de função para uma macro. Ao utilizar bzero através da função apontadores, isto não vai funcionar.
 1
Author: Bruce, 2015-04-30 00:18:43