Em uma aula de Programação de Sistemas que fiz neste semestre anterior, tivemos que implementar um cliente / servidor básico em C. Ao inicializar estruturas, como sock_addr_in
ou buffers de char (que usamos para enviar dados entre cliente e servidor), o professor nos instruiu a usar apenas bzero
e não memset
inicializá-los. Ele nunca explicou o porquê e estou curioso para saber se existe uma razão válida para isso.
Vejo aqui: http://fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdown que bzero
é mais eficiente devido ao fato de que apenas zerará a memória, por isso não precisa fazer qualquer 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
é considerado obsoleto e, além disso, não é uma função C padrão. De acordo com o manual, memset
é preferível a bzero
esse motivo. Então, por que você iria querer ainda usam bzero
mais memset
? Apenas pelos ganhos de eficiência, ou é algo mais? Da mesma forma, quais são os benefícios do memset
excesso bzero
que o tornam a opção preferida de fato para programas mais recentes?
fonte
memset
pode ser um pouco menos eficiente por causa de "um pouco mais de verificação" é definitivamente um caso de otimização prematura: quaisquer que sejam os ganhos que você pode ver ao omitir uma ou duas instruções da CPU, não valem a pena quando você pode comprometer a portabilidade do seu código.bzero
é obsoleto, e isso é motivo suficiente para não usá-lo.Respostas:
Não vejo qualquer razão para preferir
bzero
maismemset
.memset
é uma função C padrão, emborabzero
nunca tenha sido uma função padrão C. A lógica é provavelmente porque você pode obter exatamente a mesma funcionalidade usando amemset
funçãoAgora, com relação à eficiência, os compiladores
gcc
usam implementações embutidas paramemset
quais alternam para uma implementação específica quando uma constante0
é detectada. O mesmo paraglibc
quando os recursos internos estão desativados.fonte
memset
sempre deveria ser usado nesse caso, mas estava confuso sobre o motivo de não usá-lo. Obrigado por esclarecer e reafirmar meus pensamentos.bzero
implementações quebradas . Em matrizes não alinhadas, costumava ultrapassar o comprimento fornecido e zerar um pouco mais bytes. Nunca tive esse problema depois de mudar paramemset
.memset_s
qual deve ser usado se você quiser garantir que o compilador não otimize silenciosamente uma chamada para "limpar" a memória para algum propósito relacionado à segurança (como apagar uma região da memória que continha uma informação sensível). informações, como uma senha de texto não criptografado).Acho que você usou (ou seu professor foi influenciado por) UNIX Network Programming por W. Richard Stevens. Ele usa com
bzero
frequência, em vez dememset
, mesmo na edição mais atualizada. O livro é tão popular que acho que se tornou um idioma na programação de redes, e é por isso que você ainda o vê sendo usado.Eu ficaria com
memset
simplesmente porquebzero
é preterido e reduz a portabilidade. Duvido que você tenha algum ganho real ao usar um sobre o outro.fonte
A única vantagem que acho
bzero()
que sobroumemset()
para configurar a memória como zero é que há uma chance reduzida de cometer um erro.Mais de uma vez me deparei com um bug que parecia:
O compilador não irá reclamar (embora talvez aumente alguns níveis de aviso em alguns compiladores) e o efeito será que a memória não é limpa. Como isso não descarta o objeto - apenas o deixa em branco - há uma chance decente de que o bug não se manifeste em nada óbvio.
O fato de
bzero()
não ser padrão é um irritante menor. (FWIW, eu não ficaria surpreso se a maioria das chamadas de função nos meus programas não fosse padrão; de fato, escrever essas funções é o meu trabalho).Em um comentário a outra resposta aqui, Aaron Newton citou o seguinte em Unix Network Programming, Volume 1, 3rd Edition por Stevens, et al., Seção 1.2 (ênfase adicionada):
Também acredito que a grande maioria das chamadas para
memset()
a memória é zero, então por que não usar uma API que é personalizada para esse caso de uso?Uma possível desvantagem
bzero()
é que é mais provável que os compiladores otimizemmemcpy()
porque é padrão e, portanto, eles podem ser escritos para reconhecê-lo. No entanto, lembre-se de que o código correto ainda é melhor que o código incorreto que foi otimizado. Na maioria dos casos, o usobzero()
não causará um impacto perceptível no desempenho do programa ebzero()
pode ser uma função macro ou embutida que se expande paramemcpy()
.fonte
memset()
chamadas é simplesmente zerar um bloco de memória, o que eu acho que é outro argumentobzero()
. O que significa o 'b'bzero()
de qualquer maneira?memset
viola uma ordem comum de parâmetros de "buffer, buffer_size", tornando-o IMO particularmente propenso a erros.Queria mencionar algo sobre o argumento bzero vs. memset. Instale o ltrace e compare o que ele faz sob o capô. No Linux com libc6 (2.19-0ubuntu6.6), as chamadas feitas são exatamente as mesmas (via
ltrace ./test123
):Foi-me dito que, a menos que eu esteja trabalhando nas entranhas profundas da libc ou em qualquer número de interfaces kernel / syscall, não preciso me preocupar com elas. Tudo o que me preocupa é que a chamada atenda ao requisito de zerar o buffer. Outros mencionaram sobre qual é preferível em relação ao outro, então vou parar por aqui.
fonte
memset(ptr, 0, n)
quando veembzero(ptr, n)
e não podem convertê-lo em código embutido.extern void bzero(void *, size_t); void clear(void *p, size_t n) { bzero(p, n); }
produz uma chamada paramemset
. (Incluastddef.h
parasize_t
sem qualquer outra coisa que possa interferir.)Você provavelmente não deveria usar
bzero
, não é realmente C padrão, era uma coisa do POSIX.E observe que a palavra "was" - foi preterida no POSIX.1-2001 e removida no POSIX.1-2008 em deferência ao memset, para que você esteja melhor usando a função C padrão.
fonte
bzero
não faz parte disso.Para a função memset, o segundo argumento é um
int
e o terceiro argumento ésize_t
,que normalmente é um
unsigned int
, mas se os valores como,0 and 16
para o segundo e terceiro argumento, respectivamente, forem inseridos na ordem errada como 16 e 0, essa chamada para memset ainda poderá funcionar, mas não fará nada. Porque o número de bytes a inicializar são especificados como0
.Esse erro pode ser evitado usando o bzero, porque a troca dos dois argumentos pelo bzero sempre será capturada pelo compilador C se forem utilizados protótipos de função.
fonte
Em resumo:
memset
exija mais operações de montagembzero
.Esta é a fonte: http://fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdown
fonte
Faça como quiser. :-)
Observe que:
bzero
não retorna nada,memset
retorna o ponteiro nulo (d
). Isso pode ser corrigido adicionando o typecast a anular na definição.#ifndef bzero
não impede que você esconda a função original, mesmo que ela exista. Ele testa a existência de uma macro. Isso pode causar muita confusão.bzero
ponteiros de função, isso não funcionará.fonte
bzero
ponteiros de função, isso não funciona.bzero
. Isso é uma atrocidade.O memset usa 3 parâmetros, o bzero ocupa 2 na memória restrita, que o parâmetro extra levaria mais 4 bytes e na maioria das vezes será usado para definir tudo como 0
fonte