[C con Clase] Tamaño de Buffer

Steven Davidson srd4121 en njit.edu
Jue Jun 3 02:01:27 CEST 2010


Hola José Luis,

anonymous.mx wrote:
> Muchas gracias Steven por las observaciones acertadas.
> 
> No he entrado a la etapa de depuración total del codigo, pero siempre 
> una buena organización desde el principio es mejor.
> 
> Soy programador empirico, me gusta hacer el codigo partiendo de una 
> idea, compilar y probar.
> 

Sé que es más divertido ponerse a escribir código, pero recomiendo que 
tengas la solución diseñada con anterioridad. Te ahorrarás muchos 
quebraderos de cabeza.

> Agrego los siguiente comentarios.
> 
> _trched es tipo char con 240 posiciones (char _trched [240];), al 

Sospecho que '_trched' representa los bytes leídos del fichero, sin 
aplicar ningún procesamiento a tales datos.

> comenzar el codigo tuve muchos problemas para obtener un valor entero
> de 4 bytes o de 2 bytes, por lo que se me ocurrio hacer las 2
> funciones de valores enteros para 2 y 4 bytes. (unsigned char
> int2[2];   unsigned char int4[4];) (ademas de que funcionara tanto en
> windows, linux y solaris)
> 

Para esto, sugiero usar las directivas del precompilador para elegir y 
establecer las funciones, o posiblemente las macros, y los tipos de dato 
a usarse en el código fuente. De esta manera, puedes usar un solo 
conjunto de entidades con el mismo nombre. Por ejemplo,

#ifdef MS_WINDOWS
   typedef short int ENTERO2;
   typedef long int ENTERO4;
   #define entero2(a) ...
   #define entero4(a) ...
#else
#ifdef LINUX
   typedef short int ENTERO2;
   typedef long int ENTERO4;
   #define entero2(a) ...
   #define entero4(a) ...
#else
#ifdef SOLARIS
   typedef __int16 ENTERO2;
   typedef __int32 ENTERO4;
   #define entero2(a) ...
   #define entero4(a) ...
#endif

Usaríamos estas definiciones en el resto del código fuente. Por ejemplo,

int main()
{
   ...
   ENTERO2 num = entero2( &_trched[17-1] );
   ENTERO4 num2 = entero4( &_trched[32] );
   ...
}

Como puedes ver, este código funcionará correctamente dependiendo de las 
definiciones que elijamos al comienzo, que corresponden a la constante 
simbólica definida: MS_WINDOWS, LINUX, o SOLARIS. La cuestión es que no 
tenemos que cambiar el código fuente según la plataforma en la que 
queremos compilarlo.

> int entero2(unsigned char* s)
> {
>  int ret;
>  ret = s[0] * 256;
>  ret = ret + s[1];
>  if (ret>32767) ret = ret - 65536;
>  return ret;
> }
> long int entero4(unsigned char* s)
> {
>  long int ret;
>  ret = s[0] * 16777216;
>  ret = ret + s[1] * 65536;
>  ret = ret + s[2] * 256;
>  ret = ret + s[3];
>  if (ret>2147483647) ret = ret - 2147483646;
>  return ret;
> }
> 

Entiendo lo que quieres hacer, pero nada de esto es necesario en C/C++. 
La solución es simplemente realizar un cásting correcto a la información 
para que el compilador la trate de diferente manera. Por ejemplo,

short int entero2( const unsigned char *ptr )
{
   int *pNum = (int *)ptr;
   return *pNum;
}

Indicamos al compilador que la dirección de memoria en 'ptr' es copiada 
como un puntero a 'short int'. Por lo tanto, al acceder a la información 
apuntada, ésta es tratada como un 'short int'.

Lo mismo podemos hacer con 'entero4()', haciendo un cásting a 'long int'.

Huelga decir que esto funcionará si el formato numérico en el fichero 
coincide con el de la plataforma. Esto tiene que ver con el tratamiento 
de la información en memoria por parte del procesador. Algunos 
procesadores interpretan el orden de la información de una manera y 
otros de la forma inversa. Por ejemplo, Intel interpreta una serie de 
bytes que representa un número entero (little endian) de diferente forma 
que un SPARC (big endian, aunque los modernos son "bi-endian").

> 
> Cuando se realiza el fread la variable _trched obtiene 240 bytes del 
> archivo en la posicion que indica el for.
> 
> Entonces desde la posicion 17-1 hasta 17+2 se encuentra el valor
> entero de 4 bytes que quiero leer y comparar contra la variable SP,
> si la traza tiene el valor del SP procedo a grabar la traza completa
> en nuevo archivo.
> 
> Por lo que me tiene intrigado estas instrucciones que me comentaste.
> 
> 
> entero4( &_trched[17-1] )
> 
> O de su forma equivalente:
> 
> entero4( _trched + 17-1 )
> 

Básicamente, estamos pasando el puntero a la información que quieres. No 
es necesario copiar la información a otro array, porque la información 
no cambia. Es como si hicieras esto:

int temp = num;

if( VALOR == temp ) ...

Podríamos ahorrarnos esa variable temporal, 'temp', y usar 'num' 
directamente.

En el caso de '_trched', se trata de un array de bytes, por lo que 
pasamos la dirección de memoria del comienzo del "subarray" que nos 
interesa. En tu caso, nos interesa el "subarray": '_trched[17-1]' a 
'_trched[17+2]'. Lo principal es que este subarray empieza por la 
dirección de memoria de '_trched[17-1]'. Esto es justo lo que hacemos 
con las expresiones anteriores.


Espero haber aclarado el tema.

Steven




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