[C con Clase] Que problemas puede causar memcpy al introducir un buffer de datos en un struct

Salvador Pozo salvador en conclase.net
Lun Oct 8 12:03:10 CEST 2012


El pasado 2012-10-07 22:10:00, marta vic escribió:
 
mv> Hola
mv> Tengo una duda, y busco mas lugares donde pueda acceder a explicaciones o
mv> documentacion que una explicacion concreta,
mv> me gustaria definir los problemas que se pueden encontrar al intentar
mv> ejecutar un codigo como este:
mv> memcpy(&estructura1,"\x00\x00\x00\x00\x00\x00\x00\x00",8);
mv> en este caso
mv> estructura1{
mv>     int a;
mv>     int b;
mv> }

Hola:

Antes de ver qué problemas puede haber en este mecanismo, comentar que existen soluciones mejores para hacer lo que se pretende.

En la misma biblioteca que memcpy existe otra función, memset, que está diseñada específicamente para esa tarea.

En tu caso concreto, podría usarse de este modo:

----8<------
struct {
    int a;
    int b;
} estructura1;

memset(&estructura1,0,sizeof(structura1));
----8<------

Esto tiene algunas ventajas evidentes:
1) No necesitas una cadena de ceros de longitud arbitraria, ya que usamos un único valor de tipo int, que se usará como un byte (un unsigned char).
2) No tenemos que usar una constante como tamaño de la estructura, en su lugar usamos en operador sizeof, que nos da el tamaño exacto de la estructura, independientemente de la arquitectura y de la alineación de bytes usada.

Respondiendo a tu pregunta, ahora no puedo decirte un lugar donde puedas encontrar información sobre ese tema, sobre todo, porque no sé si existe algo tan concreto.

Los problemas son, entre otros, los que ha indicado José Luis:

- Dependiendo de la plataforma y del compilador, los valores enteros pueden tener distintos tamaños. En general, el tamaño de una estructura estará determinado por el tamaño de cada uno de sus componentes, y en C ese tamaño no está definido, salvo que el de int es mayor o igual que char, y el de long int mayor o igual que int. (http://c.conclase.net/curso/index.php?cap=002#inicio)

- Otro problema es el de alineación de las variables en memoria. A menudo, para mejorar la eficacia de los procesadores a la hora de acceder a memoria, las direcciones de las variables pueden ser múltiplos de 2, de 4 o de 8, dependiendo del tamaño de la palabra del microprocesador.
(http://c.conclase.net/curso/index.php?cap=011b#inicio)

Por ejemplo, en esta estructura:
struct A {
   int x;
   char a;
   int y;
   char b;
};

Si el alineamiento es de cuatro bytes, las posiciones de memoria de cada elemento del array no serán consecutivas:
0-3: x
4: a
5-7: libre
8-11: y
12: b
13-15: libre

De este modo, una estructura que debería ocupar 10 bytes, en realidad ocupa 16.

Es más, el tamaño final puede depender del orden en que se declaran los elementos de la estructura, y de si se activa o no el alineamiento de bytes.

- El problema con el formato Big Endian o Little Endian, en el caso concreto de inicializar con ceros, no tiene importancia. Otro tema sería si los valores iniciales no fueran nulos.

- Por último, los problemas son casi iguales si se trata de arrays o estructuras. En los dos casos nos afecta la arquitectura y el problema del alineamiento de bytes.

En cuanto a soluciones, arriba te he comentado la que se suele usar en C, que consiste en utilizar la función memset.

En C++ es preferible usar constructores, al menos en el caso de estructuras, ya que para los arrays puede interesar más usar memset también.

En general, no es buena idea que el programador haga las cuentas si puede hacer que las haga el compilador. Para hacer las cuentas a mano, como en tu ejemplo, debemos asumir el tamaño de las variables y cierta alineación, pero eso hace que el programa no sea transportable, y no podemos garantizar que funcione correctamente si se compila en otra plataforma, con otro sistema operativo o con otro compilador.

Seguramente encuentres documentación en la red haciendo consultas con:
memcpy gibendian
memcpy alineamiento bytes
memcpy plataformas

Suerte, y hasta pronto.

-- 
Salvador Pozo (Administrador)
mailto:salvador en conclase.net


Más información sobre la lista de distribución Cconclase