studio reales proyectos programacion libro introducción incluye herramientas fundamentos fuente español código con avanzado aplicaciones c++ c memory-management buffer

c++ - reales - libro de android studio en español pdf



¿Qué sucede si escribo menos de 12 bytes en un búfer de 12 bytes? (10)

Comprensiblemente, pasar un error de búfer (o crear un desbordamiento), pero ¿qué sucede si se usan menos de 12 bytes en un búfer de 12 bytes? ¿Es posible o el final vacío siempre se llena con 0s? Pregunta ortogonal que puede ayudar: ¿qué contiene un búfer cuando se crea una instancia pero aún no es utilizado por la aplicación?

He visto algunos programas para mascotas en Visual Studio y parece que están agregados con 0s (o caracteres nulos) pero no estoy seguro si esta es una implementación de MS que puede variar según el idioma / compilador.


C ++ tiene clases de almacenamiento que incluyen global, automático y estático. La inicialización depende de cómo se declara la variable.

char global[12]; // all 0 static char s_global[12]; // all 0 void foo() { static char s_local[12]; // all 0 char local[12]; // automatic storage variables are uninitialized, accessing before initialization is undefined behavior }

Algunos detalles interesantes here .


Considera tu búfer, lleno de ceros:

[00][00][00][00][00][00][00][00][00][00][00][00]

Ahora, vamos a escribirle 10 bytes. Valores que se incrementan desde 1:

[01][02][03][04][05][06][07][08][09][10][00][00]

Y ahora otra vez, esta vez, 4 veces 0xFF:

[FF][FF][FF][FF][05][06][07][08][09][10][00][00]

¿Qué sucede si se utilizan menos de 12 bytes en un búfer de 12 bytes? ¿Es posible o el final vacío siempre se llena con 0s?

Escribes todo lo que quieras, los bytes restantes se mantienen sin cambios.

Pregunta ortogonal que puede ayudar: ¿qué contiene un búfer cuando se crea una instancia pero aún no es utilizado por la aplicación?

Sin especificar. Espere basura dejada por los programas (u otras partes de su programa) que usaron esta memoria antes.

He visto algunos programas para mascotas en Visual Studio y parece que están agregados con 0s (o caracteres nulos) pero no estoy seguro si esta es una implementación de MS que puede variar según el idioma / compilador.

Es exactamente lo que crees que es. Alguien lo había hecho por ti esta vez, pero no hay garantías de que vuelva a suceder. Podría ser un indicador de compilador que adjunta el código de limpieza. Algunas versiones de MSVC solían llenar memoria nueva con 0xCD cuando se ejecutaban en depuración pero no en versión. También puede ser una función de seguridad del sistema que borra la memoria antes de asignarla a su proceso (por lo que no puede espiar otras aplicaciones). Recuerda siempre usar memset para inicializar tu búfer donde sea importante. Eventualmente, ordene el uso de cierta marca de compilador en el archivo Léame si depende de un búfer nuevo para que contenga un cierto valor.

Pero la limpieza no es realmente necesaria. Se toma un búfer de 12 bytes. Lo llenas con 7 bytes. Luego lo pasas a algún lugar, y dices "aquí hay 7 bytes para ti". El tamaño del búfer no es relevante cuando se lee de él. Usted espera que otras funciones lean tanto como ha escrito, no tanto como sea posible. De hecho, en C generalmente no es posible decir cuánto dura el búfer.

Y una nota al margen:

Comprensiblemente, repasando los errores de un búfer (o crea un desbordamiento)

No es así, ese es el problema. Por eso es un gran problema de seguridad: no hay ningún error y el programa intenta continuar, por lo que a veces ejecuta el contenido malicioso que nunca tuvo la intención de hacerlo. Así que tuvimos que agregar un montón de mecanismos al sistema operativo, como ASLR, que aumentará la probabilidad de que el programa se bloquee y disminuirá la probabilidad de que continúe con la memoria dañada. Por lo tanto, nunca dependas de esos guardias de último momento y observa tus límites de amortiguación.


Creo que la respuesta correcta es que siempre debes llevar un registro de cuántos caracteres se escriben. Al igual que con las funciones de bajo nivel, como la lectura y la escritura, o la cantidad de caracteres leídos o escritos. De la misma manera, std :: string mantiene un seguimiento del número de caracteres en su implementación


Depende del especificador de la clase de almacenamiento, su implementación y su configuración. Algunos ejemplos interesantes: - Las variables de la pila sin inicializar se pueden establecer en 0xCCCCCCCC - Las variables del montón sin inicializar se pueden configurar en 0xCDCDCDCD - Las variables globales o estáticas sin inicializar se pueden configurar en 0x00000000 - o podría ser basura. Es arriesgado hacer suposiciones sobre esto.


El programa conoce la longitud de una cadena porque la termina con un terminador nulo, un carácter de valor cero.

Esta es la razón por la que para ajustar una cadena en un búfer, el búfer tiene que ser al menos 1 carácter más largo que el número de caracteres en la cadena, para que pueda encajar la cadena más el terminador nulo también.

Cualquier espacio después de eso en el búfer se deja intacto. Si había datos allí anteriormente, todavía está allí. Esto es lo que llamamos basura.

Es incorrecto suponer que este espacio se llena con cero solo porque aún no lo ha utilizado, no sabe para qué se utilizó ese espacio de memoria en particular antes de que su programa llegara a ese punto. La memoria no inicializada debe manejarse como si su contenido fuera aleatorio y poco confiable.


En general, no es en absoluto inusual que los buffers estén llenos. A menudo es una buena práctica asignar buffers más grandes de lo que deben ser. (Tratar de calcular siempre el tamaño exacto del búfer es una fuente frecuente de error y, a menudo, una pérdida de tiempo).

Cuando un búfer es más grande de lo que debe ser, cuando el búfer contiene menos datos que su tamaño asignado, es obviamente importante hacer un seguimiento de la cantidad de datos que hay. En general, hay dos formas de hacerlo: (1) con un recuento explícito, mantenido en una variable separada, o (2) con un valor "centinela", como el carácter /0 que marca el final de una cadena en C .

Pero luego está la pregunta, si no se está utilizando todo un búfer, ¿qué contienen las entradas no utilizadas?

Una respuesta es, por supuesto, que no importa . Eso es lo que significa "no utilizado". Se preocupa por los valores de las entradas que se utilizan, que se contabilizan por su cuenta o su valor de centinela. No te importan los valores no utilizados.

Básicamente, existen cuatro situaciones en las que puede predecir los valores iniciales de las entradas no utilizadas en un búfer:

  1. Cuando asigna una matriz (incluida una matriz de caracteres) con una duración static , todas las entradas no utilizadas se inicializan en 0.

  2. Cuando asigna una matriz y le da un inicializador explícito, todas las entradas no utilizadas se inicializan a 0.

  3. Cuando llama a calloc , la memoria asignada se inicializa a todos los bits-0.

  4. Cuando llama a strncpy , la cadena de destino se rellena hasta tamaño n con /0 caracteres.

En todos los demás casos, las partes no utilizadas de un búfer son impredecibles y generalmente contienen lo que hicieron la última vez (lo que sea que eso signifique). En particular, no puede predecir el contenido de una matriz no inicializada con duración automática (es decir, una que es local para una función y no está declarada con static ), y no puede predecir el contenido de la memoria obtenida con malloc . (Algunas veces, en esos dos casos, la memoria tiende a comenzar con todos los bits a cero la primera vez, pero definitivamente no querrá depender de esto).


Escribir parte de un búfer no afectará a la parte no escrita del búfer; contendrá todo lo que había allí de antemano (lo que, naturalmente, depende completamente de cómo obtuviste el búfer en primer lugar).

Como señalan las otras respuestas, las variables estáticas y globales se inicializarán a 0 , pero las variables locales no se inicializarán (y en su lugar contendrán lo que había en la pila de antemano). Esto se ajusta al principio de cero sobrecarga: la inicialización de las variables locales sería, en algunos casos, un costo de tiempo de ejecución innecesario y no deseado, mientras que las variables estáticas y globales se asignan en el tiempo de carga como parte de un segmento de datos.

La inicialización del almacenamiento en el montón es a opción del administrador de memoria, pero en general tampoco se inicializará.


Los objetos declarados de duración estática (aquellos declarados fuera de una función, o con un calificador static ) que no tienen un inicializador especificado se inicializan a cualquier valor que esté representado por un cero literal [es decir, un cero entero, un punto flotante cero o un puntero nulo, según corresponda, o una estructura o unión que contenga dichos valores]. Si la declaración de cualquier objeto (incluidos los de duración automática) incluye un inicializador, las partes cuyos valores están especificados por ese inicializador se establecerán como se especificó, y el resto se pondrá a cero como con los objetos estáticos.

Para objetos automáticos sin inicializadores, la situación es algo más ambigua. Dado algo como:

#include <string.h> unsigned char static1[5], static2[5]; void test(void) { unsigned char temp[5]; strcpy(temp, "Hey"); memcpy(static1, temp, 5); memcpy(static2, temp, 5); }

el Estándar es claro que la test no invocaría un comportamiento indefinido, aunque copia partes de temp que no se inicializaron. El texto de la Norma, al menos a partir de C11, no está claro si se garantiza algo acerca de los valores de static1[4] y static2[4] , sobre todo si se pueden dejar con valores diferentes. Un informe de defectos indica que la Norma no tenía la intención de prohibir que un compilador se comporte como si el código hubiera sido:

unsigned char static1[5]={1,1,1,1,1}, static2[5]={2,2,2,2,2}; void test(void) { unsigned char temp[4]; strcpy(temp, "Hey"); memcpy(static1, temp, 4); memcpy(static2, temp, 4); }

que podría dejar static1[4] y static2[4] con diferentes valores. La Norma no dice si los compiladores de calidad destinados a diversos propósitos deberían comportarse en esa función. El Estándar tampoco ofrece orientación sobre cómo se debe escribir la función si la intención si el programador requiere que static1[4] y static2[4] tengan el mismo valor, pero no importa cuál sea ese valor.


Todas las respuestas anteriores son muy buenas y muy detalladas, pero el OP parece ser nuevo en la programación en C. Entonces, pensé que un ejemplo del mundo real podría ser útil.

Imagina que tienes un soporte de cartón para bebidas que puede contener seis botellas. Ha estado sentado en su garaje, así que en lugar de seis botellas, contiene varias cosas desagradables que se acumulan en las esquinas de los garajes: arañas, casitas de ratones, y otros.

Un búfer de computadora es un poco como esto justo después de asignarlo. Realmente no puedes estar seguro de lo que contiene, solo sabes lo grande que es.

Ahora, digamos que pones cuatro botellas en tu soporte. Su titular no ha cambiado de tamaño, pero ahora sabe lo que hay en cuatro de los espacios. Los otros dos espacios, completos con sus contenidos cuestionables, siguen ahí.

Los buffers de computadora son de la misma manera. Es por eso que con frecuencia ve una variable bufferSize para rastrear qué cantidad del búfer está en uso. Un nombre mejor podría ser numberOfBytesUsedInMyBuffer pero los programadores tienden a ser locamente tersos.


Tome el siguiente ejemplo (dentro de un bloque de código, no global):

char data[12]; memcpy(data, "Selbie", 6);

O incluso este ejemplo:

char* data = new char[12]; memcpy(data, "Selbie", 6);

En los dos casos anteriores, los primeros 6 bytes de data son S , e , l , b , i y e . Los 6 bytes de data restantes se consideran "no especificados" (podría ser cualquier cosa).

¿Es posible o el final vacío siempre se llena con 0s?

No está garantizado en absoluto. El único asignador que conozco que garantiza el llenado de cero bytes es calloc . Ejemplo:

char* data = calloc(12,1); // will allocate an array of 12 bytes and zero-init each byte memcpy(data, "Selbie");

¿Qué contiene un búfer cuando se crea una instancia pero aún no es utilizado por la aplicación?

Técnicamente, según los estándares de C ++ más recientes, los bytes entregados por el asignador se consideran técnicamente "no especificados". Debes asumir que son datos de basura (cualquier cosa). No hagas suposiciones sobre el contenido.

Las construcciones de depuración con Visual Studio a menudo inicializan los buffers con valores 0xcd o 0xcd , pero ese no es el caso en las versiones de lanzamiento. Sin embargo, hay indicadores de compilación y técnicas de asignación de memoria para Windows y Visual Studio donde puede garantizar asignaciones de memoria de inicio cero, pero no es portátil.