utiliza que para bzero c memset systems-programming

que - strcat



¿Por qué usar bzero sobre memset? (8)

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, como sock_addr_in , o los búferes de char (que solíamos enviar y sock_addr_in datos entre el cliente y el servidor) el El profesor nos indicó que solo bzero y no memset para inicializarlos. Él nunca explicó por qué, y tengo curiosidad de saber 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 va a poner a cero la memoria, por lo que no funciona Tengo que hacer cualquier verificación adicional que memset pueda hacer. Sin embargo, eso no necesariamente parece una razón para no usar memset para poner a cero la memoria.

bzero se considera obsoleto y, además, no es una función C estándar. De acuerdo con el manual, memset es preferido sobre bzero por este motivo. Entonces, ¿por qué querrías seguir usando bzero sobre 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 lo convierten en la opción preferida de facto para los programas más nuevos?


Hazlo como quieras. :-)

#ifndef bzero #define bzero(d,n) memset((d),0,(n)) #endif

Tenga en cuenta que:

  1. El bzero original bzero devuelve nada, memset devuelve el puntero void ( d ). Esto puede solucionarse agregando el tipocast a nulo en la definición.
  2. #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.
  3. Es imposible crear un puntero a una macro. Al usar bzero través de punteros de función, esto no funcionará.

La única ventaja que creo que bzero() tiene sobre memset() 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 parecía:

memset(someobject, size_of_object, 0); // clear object

El compilador no se quejará (aunque tal vez genere algunos niveles de advertencia en algunos compiladores) y el efecto será que la memoria no se borrará. Como esto no destruye el objeto, simplemente lo deja en paz, existe la posibilidad 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 de función en mis programas no son estándar, de hecho, la escritura de tales funciones es una especie de trabajo).

En un comentario a otra respuesta aquí, Aaron Newton citó lo siguiente de Unix Network Programming, Volumen 1, 3ra Edición por Stevens, et al., Sección 1.2 (énfasis agregado):

bzero no es una función ANSI C. Se deriva del código de red de Berkely. Sin embargo, lo usamos en todo el texto, en lugar de la función memset ANSI C, porque bzero es más fácil de recordar (con solo dos argumentos) que memset (con tres argumentos). Casi todos los proveedores que admiten sockets API también proporcionan bzero , y si no, proporcionamos una definición de macro en nuestro encabezado unp.h

De hecho, el autor de TCPv3 [TCP / IP Illustrated, Volumen 3 - Stevens 1996] cometió el error de intercambiar los argumentos segundo y tercero a memset en 10 ocurrencias en la primera impresión . El compilador de CA no puede detectar este error porque ambos argumentos son del mismo tipo. (En realidad, el segundo argumento es un int y el tercer argumento es size_t , que normalmente es unsigned int , pero los valores especificados, 0 y 16, respectivamente, siguen siendo aceptables para el otro tipo de argumento.) La llamada a memset todavía funcionó, porque solo algunas de las funciones de socket realmente requieren que los 8 bytes finales de una estructura de direcciones de socket de Internet se establezcan en 0. Sin embargo, era un error, y uno que se podía evitar usando bzero , porque intercambiaba los dos argumentos to bzero siempre será capturado por el compilador C si se usan prototipos de funciones.

También creo que la gran mayoría de las llamadas a memset() son cero memoria, ¿por qué no utilizar una API que se adapta a ese caso de uso?

Un posible inconveniente de bzero() es que es más probable que los compiladores optimicen memcpy() porque es estándar y por lo tanto se pueden escribir para reconocerlo. Sin embargo, tenga en cuenta que el código correcto es aún mejor que el código incorrecto que se ha optimizado. En la mayoría de los casos, usar bzero() no causará un impacto notable en el rendimiento de su programa, y ​​ese bzero() puede ser una función macro o en línea que se expande a memcpy() .


No veo ninguna razón para preferir bzero a memset .

memset es una función C estándar, mientras que bzero nunca ha sido una función estándar C. El motivo es probablemente porque puede lograr exactamente la misma funcionalidad usando la función memset .

Ahora, con respecto a la eficiencia, los compiladores como gcc usan implementaciones memset para memset que cambian a una implementación particular cuando se detecta una constante 0 . Lo mismo para glibc cuando los builtins están deshabilitados.


Para la función memset, el segundo argumento es un int y el tercer argumento es size_t ,

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

que normalmente es un unsigned int , pero si los valores como 0 and 16 para el segundo y tercer argumento, respectivamente, se ingresan en un orden incorrecto como 16 y 0, tal llamada a memset puede seguir funcionando, pero no hará nada. Porque el número de bytes para inicializar se especifica como 0 .

void bzero(void *s, size_t n)

Tal error puede evitarse usando bzero, ya que el compilador C siempre captará el intercambio de los dos argumentos a bzero si se usan prototipos de función.


Probablemente no deberías usar bzero , en realidad no es C estándar, era algo POSIX.

Y tenga en cuenta que la palabra "era" - fue desaprobada en POSIX.1-2001 y eliminada en POSIX.1-2008 en deferencia a memset, por lo que es mejor que utilice la función C estándar.


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 (a través de 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)

Me han dicho que a menos que esté trabajando en las entrañas profundas de libc o 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 buffer. Otros han mencionado sobre cuál es preferible sobre el otro, así que me detendré aquí.


Supongo que usaste (o tu profesor fue influenciado por) Programación de red UNIX por W. Richard Stevens. Utiliza bzero frecuencia en lugar de memset , incluso en la edición más actualizada. El libro es tan popular, creo que se ha convertido en una expresión idiomática en la programación de redes, razón por la cual todavía se ve utilizado.

Me quedaría con memset simplemente porque bzero está en desuso y reduce la portabilidad. Dudo que veas algún beneficio real al usar uno sobre el otro.