[C con Clase] Serializar variables
Steven Davidson
srd4121 en njit.edu
Sab Mar 13 18:39:52 CET 2010
Hola Ferrán,
Ferran Ferri wrote:
> Hola Steven,
> muchas grecias por tu respuesta. Mi forma de hacerlo cuando fallaba
> era asi:
>
> void toArray(unsigned char* data)
> {
> int a = 3;
> long b = 444;
> int *pA = &a;
> long *pB = &b;
>
> cout << "Valor de *pA " <<*pA <<endl;
> memcpy(data,(unsigned char*)pA,sizeof(int));
> data+=sizeof(int);
> cout << "Valor de *pB " <<*pB <<endl;
> memcpy(data,(unsigned char*)pB,sizeof(long));
> data+=sizeof(long);
> }
> Y fallaba por el incremento de data (lo hacia mal aunque no se por
> que. Asi se corregia:
>
No. No es cierto. He probado tu función y funciona (valga la
redundancia) perfectamente.
> void toArray(unsigned char* data)
> {
> int a = 3;
> long b = 444;
> int *pA = &a;
> long *pB = &b;
>
> cout << "Valor de *pA " <<*pA <<endl;
> memcpy(data,(unsigned char*)pA,sizeof(int));
> cout << "Valor de *pB " <<*pB <<endl;
> memcpy(data + sizeof(int),(unsigned char*)pB,sizeof(long));
> data+=sizeof(long);
> }
>
Esta versión es prácticamente la misma que la primera. Eso sí, la última
asignación no es necesaria:
datos += sizeof(long);
ya que hemos terminado.
> Tu solucion, sin embargo, me parece mucho mas elegante. Pero me
> genera dudas. Que diferencia hay entre reinterpret cast y static cast
> ademas de que static cast fuerza el que se haga en tiempo de
El operador 'reinterpet_cast' sirve para dejar la secuencia de bits
intacta. Esto significa que el tipo de dato de tal secuencia de bits
varía. El operador 'static_cast' puede modificar los bits yendo de un
tipo a otro.
> compilacion? Y la segunda duda es que cuando se acumulan variables no
> puedo ir sumando cada vez para ponerme en la posicion del array.
> Serviria algo como
> *reinterpret_cast< int * >( data++ ) = a;
> *reinterpret_cast< long * >( data++ ) = b; // si tuvieramos que meter
> mas variables
> Al haber reinterpretado el puntero, y hacer post incremento,
> avanzariamos un int en la primera sentencia y un long en la segunda,
> no es asi?
>
No. Nunca se cambia el tipo de la variable sino el tipo del valor. La
variable 'data' ha sido definida como 'unsigned char *' y nunca se puede
cambiar. Lo que sí podemos hacer es acceder a su valor y cambiar su
tipo. En la práctica, el compilador generará una variable temporal con
el tipo indicado y con el valor original. Por ejemplo,
double b = -1.3;
int a = static_cast< int >( b );
El compilador internamente hará algo así:
double b = -1.3;
int __temp = static_cast< int >( -1.3 );
int a = __temp;
Como puedes ver, 'b' nunca cambiará ni tampoco el valor que contiene. Lo
que se hace es crear otro valor basándose en el valor de 'b', pero sin
modificar éste.
Dicho todo esto, la respuesta a tu pregunta es que al incrementar
'data', este puntero apuntará al siguiente elemento. Como cada elemento
es 'unsigned char', el incremento será al siguiente 'char' que equivale
al siguiente byte. Para hacer el incremento a la siguiente dirección de
memoria posterior a 'int', tendrías que sumar ese tamaño en byte, ya que
'char' siempre ocupa 1 byte. Esto es,
*reinterpret_cast< int * >( data ) = a;
data += sizeof(int);
*reinterpret_cast< long * >( data ) = b;
data += sizeof(long);
> La tercera es mas offtopic. Si la funcion toArray la tengo en una
> clase (es un metodo), donde deberia hacer la reserva de memoria. El
> borrado es responsabilidad de quien usa la funcion cuando ya no la
> necesita. Pero la creacion podriamos hacerla dentro de la funcion
> (esta seria mi eleccion), puesto que ya sabemos cuanto espacio
> necesitamos, o exigir que se cree fuera, y comprobar que o sea null,
> puesto que tenemos que separar responsabilidades. Que opinais?
No es una buena práctica crear efectos secundarios en una función. Lo
que propones justamente crea este efecto secundario de adjudicar memoria
dinámicamente. Aconsejo que el array se cree fuera y así delegamos la
responsabilidad al invocador de esta función miembro.
Claro está, al usar clases, recomendaría usar un objeto de una clase
contenedora y si esta clase usa memoria dinámicamente, entonces mejor
que mejor. Por ejemplo, puedes usar la clase-plantilla 'vector'. Por
otro lado, posiblemente esto no sea lo que quieres, ya que 'toArray()'
no representaría un array fundamental, sino un objeto de la clase
'vector<unsigned char>'.
Espero haber aclarado las dudas.
Steven
Más información sobre la lista de distribución Cconclase