En una clase de Programación de Sistemas que tomé este semestre anterior, tuvimos que implementar un cliente / servidor básico en C. Al inicializar las estructuras, me gusta sock_addr_in
o buffers de char (que solíamos enviar datos de un lado a otro entre el cliente y el servidor), el profesor nos indicó que solo los usemos bzero
y no los memset
inicialicemos. Nunca explicó por qué, y tengo curiosidad si hay una razón válida para esto.
Veo aquí: http://fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdown que bzero
es más eficiente debido al hecho de que solo habrá cero memoria, por lo que no tiene que hacer cualquier verificación adicional que memset
pueda hacer. Sin embargo, eso no necesariamente parece ser una razón para no usar absolutamente memset
para poner a cero la memoria.
bzero
se considera obsoleto y, además, no es una función estándar de C. De acuerdo con el manual, memset
se prefiere bzero
por esta razón. Así que ¿por qué desea utilizar aún bzero
más memset
? ¿Solo por las ganancias de eficiencia, o es algo más? Del mismo modo, ¿cuáles son los beneficios de memset
Over bzero
que la convierten en la opción preferida de facto para los programas más nuevos?
fuente
memset
puede ser un poco menos eficiente debido a "un poco más de comprobación en marcha" es definitivamente un caso de optimización prematura: cualesquiera que sean las ganancias que pueda ver al omitir una o dos instrucciones de la CPU no valen la pena cuando puede poner en peligro la portabilidad de su código.bzero
es obsoleto, y esa es razón suficiente para no usarlo.Respuestas:
No veo ninguna razón para preferir
bzero
sobrememset
.memset
es una función estándar de C mientras quebzero
nunca ha sido una función estándar de C. La razón es probablemente porque puede lograr exactamente la misma funcionalidad utilizando lamemset
función.Ahora con respecto a la eficiencia, los compiladores
gcc
usan implementaciones incorporadas para lasmemset
cuales cambian a una implementación particular cuando0
se detecta una constante . Lo mismo paraglibc
cuando los builtins están deshabilitados.fuente
memset
siempre debería usarse en este caso, pero estaba confundido sobre por qué no lo estábamos usando. Gracias por aclarar y reafirmar mis pensamientos.bzero
implementaciones rotas . En matrices no alineadas, solía sobrepasar la longitud proporcionada y poner a cero un poco más de bytes. Nunca tuve tal problema después de cambiar amemset
.memset_s
qué debe usarse si desea asegurarse de que el compilador no optimice silenciosamente una llamada a "borrar" la memoria para algún propósito relacionado con la seguridad (como borrar una región de memoria que contenía un elemento sensible información como una contraseña de texto sin cifrar).Supongo que usaste (o tu maestro fue influenciado por) la programación de la red UNIX por W. Richard Stevens. Él usa con
bzero
frecuencia en lugar dememset
, incluso en la edición más actualizada. El libro es tan popular que creo que se ha convertido en una expresión idiomática en la programación de redes, por lo que todavía lo ves usado.Me quedaría con
memset
simplemente porquebzero
está en desuso y reduce la portabilidad. Dudo que vea ganancias reales al usar uno sobre el otro.fuente
La única ventaja que creo que
bzero()
tienememset()
para establecer la memoria en cero es que hay una posibilidad reducida de cometer un error.Más de una vez me encontré con un error que se parecía a:
El compilador no se quejará (aunque quizás aumenten algunos niveles de advertencia en algunos compiladores) y el efecto será que no se borrará la memoria. Debido a que esto no destruye el objeto, solo lo deja solo, hay una posibilidad decente de que el error no se manifieste en algo obvio.
El hecho de que
bzero()
no sea estándar es un irritante menor. (FWIW, no me sorprendería si la mayoría de las llamadas a funciones en mis programas no son estándar; de hecho, escribir esas funciones es mi trabajo).En un comentario a otra respuesta aquí, Aaron Newton citó lo siguiente de Unix Network Programming, Volumen 1, 3ra Edición de Stevens, et al., Sección 1.2 (énfasis agregado):
También creo que la gran mayoría de las llamadas a
memset()
son de memoria cero, entonces, ¿por qué no usar una API que se adapte a ese caso de uso?Un posible inconveniente
bzero()
es que es probable que los compiladores se optimicen másmemcpy()
porque es estándar y, por lo tanto, podrían escribirse para reconocerlo. Sin embargo, tenga en cuenta que el código correcto sigue siendo mejor que el código incorrecto que se ha optimizado. En la mayoría de los casos, el usobzero()
no causará un impacto notable en el rendimiento de su programa, y esobzero()
puede ser una función macro o en línea que se expandememcpy()
.fuente
memset()
llamadas son simplemente poner a cero un bloque de memoria, lo que creo que es otro argumentobzero()
. ¿Qué significa la 'b' enbzero()
cualquier caso?memset
viola un orden común de parámetros de "buffer, buffer_size" lo hace particularmente propenso a errores IMO.Quería mencionar algo sobre el argumento bzero vs. memset. Instale ltrace y luego compare lo que hace debajo del capó. En Linux con libc6 (2.19-0ubuntu6.6), las llamadas realizadas son exactamente las mismas (vía
ltrace ./test123
):Me han dicho que a menos que esté trabajando en las profundidades de libc o en cualquier número de interfaz kernel / syscall, no tengo que preocuparme por ellos. Todo lo que debería preocuparme es que la llamada satisfaga el requisito de poner a cero el búfer. Otros han mencionado sobre cuál es preferible sobre el otro, así que me detendré aquí.
fuente
memset(ptr, 0, n)
cuando lo veanbzero(ptr, n)
y no pueden convertirlo a código en línea.extern void bzero(void *, size_t); void clear(void *p, size_t n) { bzero(p, n); }
produce una llamada amemset
. (Incluirstddef.h
parasize_t
sin cualquier otra cosa que pueda interferir.)Probablemente no deberías usar
bzero
, en realidad no es C estándar, fue una cosa POSIX.Y tenga en cuenta que la palabra "era": se desaprobó en POSIX.1-2001 y se eliminó en POSIX.1-2008 en deferencia a memset, por lo que es mejor que use la función C estándar.
fuente
bzero
no es parte de eso.Para la función memset, el segundo argumento es an
int
y el tercer argumento essize_t
,que normalmente es un
unsigned int
, pero si los valores como,0 and 16
para el segundo y el tercer argumento, respectivamente, se ingresan en un orden incorrecto como 16 y 0, entonces, tal llamada a memset aún puede funcionar, pero no hará nada. Porque el número de bytes para inicializar se especifica como0
.Tal error puede evitarse usando bzero, porque intercambiar los dos argumentos a bzero siempre será captado por el compilador de C si se utilizan prototipos de funciones.
fuente
En resumen:
memset
requieren más operaciones de montaje entoncesbzero
.Esta es la fuente: http://fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdown
fuente
Hazlo como quieras. :-)
Tenga en cuenta que:
bzero
no devuelve nada,memset
devuelve el puntero vacío (d
). Esto se puede solucionar agregando el typecast para anular en la definición.#ifndef bzero
no le impide ocultar la función original, incluso si existe. Prueba la existencia de una macro. Esto puede causar mucha confusión.bzero
punteros de función, esto no funcionará.fuente
bzero
través de punteros de función, esto no funcionará.bzero
. Esto es una atrocidad.memset toma 3 parámetros, bzero toma 2 en la memoria restringida, ese parámetro adicional tomaría 4 bytes más y la mayoría de las veces se usará para configurar todo a 0
fuente