poniendo a cero la memoria

gcc 4.4.4 C89

Me pregunto qué hacen la mayoría de los progtwigdores de C cuando quieren poner a cero la memoria.

Por ejemplo, tengo un búfer de 1024 bytes. A veces hago esto:

char buffer[1024] = {0}; 

Lo que pondrá a cero todos los bytes.

Sin embargo, ¿debería declararlo así y usar memset?

 char buffer[1024]; . . memset(buffer, 0, sizeof(buffer)); 

¿Hay alguna razón real para poner a cero la memoria? ¿Qué es lo peor que puede pasar al no hacerlo?

Lo peor que puede pasar? Usted termina (sin saberlo) con una cadena que no termina en NULL, o un entero que hereda lo que sucedió a la derecha de la misma después de que imprimió en parte del búfer. Sin embargo, las cadenas no terminadas también pueden suceder de otras formas, incluso si inicializa el búfer.

Editar (de los comentarios) El fin del mundo también es una posibilidad remota, dependiendo de lo que estés haciendo.

Cualquiera de las dos es indeseable. Sin embargo, a menos que se evite por completo la memoria asignada dinámicamente, la mayoría de los buffers asignados estáticamente son bastante pequeños, lo que hace que memset() relativamente barato. De hecho, mucho más barato que la mayoría de las llamadas a calloc() para bloques dynamics, que tienden a ser más grandes que ~ 2k.

c99 contiene lenguaje con respecto a los valores de inicialización predeterminados, sin embargo, no puedo hacer que gcc -std=c99 acuerdo con eso, utilizando cualquier tipo de almacenamiento.

Sin embargo, con muchos comstackdores más antiguos (y comstackdores que no son del todo c99) todavía en uso, prefiero usar memset()

Yo prefiero enormemente

 char buffer[1024] = { 0 }; 

Es más corto, más fácil de leer y menos propenso a errores. Solo use memset en buffers asignados dinámicamente, y luego prefiera calloc .

Cuando defina el char buffer[1024] sin inicializar, obtendrá datos no definidos en él. Por ejemplo, Visual C ++ en modo de depuración se inicializará con 0xcd. En el modo Liberación, simplemente asignará la memoria y no importará lo que suceda en ese bloque desde el uso anterior.

Además, sus ejemplos demuestran el tiempo de ejecución frente a la inicialización del tiempo de comstackción. Si su char buffer[1024] = { 0 } es una statement global o estática, se almacenará en el segmento de datos del binario con sus datos inicializados, aumentando así su tamaño binario en aproximadamente 1024 bytes (en este caso). Si la definición está en una función, se almacena en la stack y se asigna en tiempo de ejecución y no se almacena en el binario. Si proporciona un inicializador en este caso, el inicializador se almacena en el binario y se realiza un equivalente de un memcpy() para inicializar el buffer en tiempo de ejecución.

Con suerte, esto te ayudará a decidir qué método funciona mejor para ti.

En este caso particular, no hay mucha diferencia. Prefiero = { 0 } sobre memset porque memset es más propenso a errores:

  • Brinda la oportunidad de equivocarse en los límites.
  • memset oportunidad de mezclar los argumentos con memset (por ejemplo, memset(buf, sizeof buf, 0) lugar de memset(buf, 0, sizeof buf) .

En general, = { 0 } es mejor para inicializar struct . Inicializa efectivamente a todos los miembros como si hubiera escrito = 0 para inicializar cada uno. Esto significa que se garantiza que los miembros del puntero se inicialicen con el puntero nulo ( que podría no ser todos los bits-cero , y todos los bits-cero es lo que obtendría si hubiera usado memset ).

Por otro lado, = { 0 } puede dejar los bits de relleno en una struct como basura, por lo que podría no ser apropiado si planea usar memcmp para compararlos más adelante.

Lo peor que puede pasar si no lo hace es que escribe algunos datos carácter por carácter y luego lo interpreta como una cadena (y no escribió un terminador nulo). O terminas sin darte cuenta de que una sección no estaba inicializada y la leías como si fuera información válida. Básicamente: todo tipo de maldad.

Memset debería estar bien (siempre que corrija el tamaño de error tipográfico :-)). Prefiero eso a tu primer ejemplo porque creo que está más claro.

Para la memoria asignada dinámicamente, uso calloc en lugar de malloc y memset.

Prefiero usar memset para borrar un trozo de memoria, especialmente cuando se trabaja con cadenas. Quiero saber sin lugar a dudas que habrá un delimitador nulo después de mi cadena. Sí, sé que puede agregar un \0 al final de cada cadena y algunas funciones lo hacen por usted, pero no quiero dudas de que esto ha tenido lugar.

Una función podría fallar al usar su búfer, y el búfer permanece sin cambios. ¿Prefieres tener un búfer de basura desconocida, o nada?

Una de las cosas que pueden suceder si no se inicializa es que corre el riesgo de filtrar información confidencial.

La memoria no inicializada puede tener algo sensible en un uso anterior de esa memoria. Tal vez una contraseña o clave de cifrado o parte de un correo electrónico privado. Más tarde, su código puede transmitir ese búfer o estructura en algún lugar, o escribirlo en el disco, y si solo lo llenó parcialmente, el rest aún contiene los contenidos anteriores. Ciertos sistemas seguros requieren buffers de ceroización cuando un espacio de direcciones puede contener información confidencial.

Esta publicación ha sido editada en gran medida para que sea correcta. Muchas gracias a Tyler McHenery por señalar lo que me perdí.

 char buffer[1024] = {0}; 

Establecerá el primer carácter en el búfer en nulo, y el comstackdor expandirá todos los caracteres no inicializados a 0 también. En tal caso, parece que las diferencias entre las dos técnicas se reducen a si el comstackdor genera un código más optimizado para la inicialización de la matriz o si memset se optimiza más rápido que el código comstackdo generado.

Anteriormente dije:

búfer de caracteres [1024] = {0};

Establecerá el primer char en el búfer en nulo. Esa técnica se usa comúnmente para cadenas terminadas en nulo, ya que todas las informaciones posteriores al primer nulo son ignoradas por las funciones posteriores (sin buggy) que manejan cadenas terminadas en nulo.

Lo cual no es del todo cierto. Lo siento por la falta de comunicación, y gracias de nuevo por las correcciones.

Depende de cómo lo llene: si planea escribirlo antes incluso de leer algo, ¿por qué molestarse? También depende para qué utilizarás el búfer: si se va a tratar como una cadena, entonces solo necesitas establecer el primer byte en \0 :

 char buffer[1024]; buffer[0] = '\0'; 

Sin embargo, si lo está utilizando como un flujo de bytes, es probable que el contenido de la matriz completa sea relevante, por lo que la memset completa o la configuración en { 0 } como en su ejemplo es un movimiento inteligente.

También uso memset (buffer, 0, sizeof (buffer));

El riesgo de no usarlo es que no hay garantía de que el búfer que está utilizando esté completamente vacío, podría haber basura que podría llevar a un comportamiento impredecible.

Siempre unir a 0 después de malloc, es una muy buena práctica.

Sí, el método calloc () definido en stdlib.h asigna memoria inicializada con ceros.

No estoy familiarizado con el

 char buffer[1024] = {0}; 

técnica. Pero suponiendo que haga lo que creo que hace, hay una diferencia (potencial) en las dos técnicas.

El primero se realiza en tiempo de comstackción, y el búfer será parte de la imagen estática del ejecutable, y por lo tanto será 0 cuando cargues.

Esto último se hará en tiempo de ejecución.

El primero puede incurrir en algún comportamiento de tiempo de carga. Si solo tienes:

 char buffer[1024]; 

los cargadores modernos bien pueden “virtualmente” cargar eso … es decir, no tomará ningún espacio real en el archivo, simplemente será una instrucción para que el cargador genere un bloque cuando se carga el progtwig. No estoy lo suficientemente cómodo con los cargadores modernos dicen si eso es cierto o no.

Pero si lo preinicializa, entonces será necesario cargarlo desde el ejecutable.

Cuidado, ninguno de estos tiene impactos “reales” de rendimiento en lo pequeño. Es posible que no tengan ninguna en el “grande”. Solo digo que hay potencial aquí, y las dos técnicas de hecho están haciendo algo muy diferente.