[C con Clase] SDL operaciones bitwise y punteros.

David xdrtas en yahoo.es
Lun Feb 28 14:19:37 CET 2011


Excelente Steven lo he entendido todo, muchas gracias por tu tiempo y esfuerzo 
:-D

Muchos saludos,
David Lastra.
 http://xdrtas.coolpage.biz/
http://xdrtas.blogspot.com/




________________________________
De: Steven Davidson <srd4121 en njit.edu>
Para: Lista de correo sobre C y C++ <cconclase en listas.conclase.net>
Enviado: sáb,26 febrero, 2011 14:06
Asunto: Re: [C con Clase] SDL operaciones bitwise y punteros.

Hola David,

On 2/26/2011 7:23 AM, David wrote:
> Steven, en serio muchísimasgracias
> 

De nada; para eso estamos.

> (Uint16 *)p -> realiza el casting; una vez realizado el casting
> entonces que vuelva a apuntar a la dirección de memoria *p, juntando
> las dos cosas da como resultado la expresión *(Uint16 *)p.
> 
> En base a esto, permíteme tratar de explicar la siguiente expresión:
> 
> Nota: superficie->pixels está definido dentro de la estructura
> SDL_Surface como un puntero a void, o sea, "void *pixels".
> 
> Uint8 *p = (Uint8 *)superficie->pixels + y * superficie->pitch + x *
> bpp;
> 
> 1.- Se realiza el casting de (void *) a (Uint8 *) sobre el puntero
> superficie->pixels.
> 2.- Se multiplica x * bpp
> 3.- Se multiplica y * superficie->pitch
> 4.- Se suma el resultado del punto 2 y 3
> 5.- Y por último el resultado del punto 4 es sumado a la dirección de
> memoria de superficie->pixels.
> 

Correcto.

> Otra forma de verlo sería así:
> Uint8 *p = (Uint8 *)superficie->pixels; //p apunta a la dirección
> superficie->pixels.
> p[ (y * superficie->pitch) + (x * bpp) ]; //obtener la dirección del
> pixel.
> 

Esto último no es correcto. Recuerda que los corchetes [] son un operador de 
acceso. Aquí accederías al píxel del índice 'y*superficie->pitch + x*bpp'.

Sin embargo, esto no es lo que hacemos, sino que obtenemos la dirección de 
memoria que apunta a un píxel; o mejor dicho, a un 'Uint8' que representa 1 solo 
byte.

> Así se obtiene la posición del pixel y nos permite luego ir a p[R],
> p[G] y p[B] sin mayor riesgo ya que para este caso cada uno de los
> pixeles está compuesto por 24 bits y p es de 8 bits, por lo que 8 x 3
> = 24. Entonces teniendo la posición del pixel en la superficie,
> podemos movernos entre los 24 bits que componen el pixel sin
> problemas debido a que R=0 G=1 B=2 son consecutivos.
> 

Exacto.

> 

[CORTE]

> Una pregunta más, la función GetPixel en mi arquitectura me devuelve
> [B, G, R], sin embargo cuando el resultado en una variable,
> llamemosle color, al verlo en hexadecimal me muestra [R, G, B]. El
> compilador hace una transformación de forma automática por ser
> little-endian?
> 

Sí; claro. Al fin y al cabo, el compilador DEBE conocer la arquitectura del 
procesador al cual va a compilar y traducir el código fuente. Si usas un 
compilador para Intel, entonces debe saber que Intel usa "little-endian".

Ahora bien, al decir que "muestra" algo (en pantalla), entonces estamos hablando 
de las funciones, segurametne estándares, de las bibliotecas que controlan la 
consola (y la pantalla). Aquí, el compilador no tiene nada que ver, ya que esa 
funcionalidad ya está compilada, en la mayoría de los casos. Por consiguiente, 
si la función que usas muestra información, ésta puede ser diferente a su 
representación interna.

> Para que veas más claro a lo que me refiero te coloco la porción de
> código:
> 
> //Defino el color que quiero mostrar en la pantalla o superficie...
> Uint32 color = SDL_MapRGB(pantalla->format, 255, 0, 0); //Color rojo..
> 
> //Pinto el pixel del color rojo en la superficie:
> PutPixel(pantalla, 100, 100, color);
> 
> //Obtengo el valor del color de la pantalla...
> Uint32 comprobar = GetPixel(pantalla, 100, 100); //Aquí se obtiene el
> valor rojo...
> 
> //Muestro el valor hexadecimal de la variable "comprobar"...
> cout << "Valor hex: " << hex << comprobar << endl;
> 
> El resultado que me da es:
> Valor hex: ff 00 00
> 
> Sin embargo, si te fijas en el retorno de la función (return p[R] |
> p[G] << 8 | p[B] << 16;) lo que interpreto es lo siguiente
> 
> Devuelve el rojo ff, desplázate 8 bits hacia la izquierda y devuelve
> el valor del verde 00, desplázate 16 bits y devuelve el valor de azul
> 00 dejando como resultado:
> 
> 00 00 ff
> 

Correcto, para una arquitectura de "little-endian", como es Intel.

> Y claro aquí me confundo porque una cosa es lo que estoy
> interpretando y otra muy distinta el valor real devuelto.
> ff 00 00 <> 00 00 ff
> 

La explicación involucra, como he dicho anteriormente, en la funcionalidad de 
'cout <<' pero ésta depende del tipo de dato que pases como parámetro. Al 
tratarse de un 'Uint32', se pasan los primeros 4 bytes contenidos en la 
variable, 'comprobar', que representan el número entero (no negativo). Por lo 
tanto, convierte correctamente el número 16711680 a hexadecimal: 0x00FF0000. 
Esto no tiene por qué representar los valores de cada byte en memoria. Por eso, 
el tipo de dato es muy importante en cuanto a la interpretación de las 
secuencias de bits y las operaciones que pueden involucrar esos valores.

En resumen, la secuencia de bytes: 0x00, 0xff, 0x00, y 0x00 es representada en 
memoria, en una arquitectura de "little-endian" como es Intel, como: 0x00, 0x00, 
0xff, y 0x00. Su interpretación depende del tipo de dato:

- Si tratas esta secuencia como un entero (no negativo) de 32 bits, entonces el 
valor es: 16711680.
- Si tratas esta secuencia como dos números enteros (no negativos) de 16 bits 
cada uno, entonces los valores son: 0, y 255.
- Si tratas esta secuencia como cuatro números enteros (no negativos) de 8 bits 
cada uno, entonces los valores son: 0, 0, 255, y 0.

Puedes hacer esta comprobación realizando un cásting apropiado al puntero, 'p', 
o incluso a la variable 'comprobar'. Por ejemplo,

cout << "Como Uint32: " << hex << comprobar << endl;

Uint16 *p16 = ((Uint16 *)&comprobar);
cout << "Como Uint16: " << hex << p16[0] << ' ' << p16[1] << endl;

Uint8 *p8 = ((Uint8 *)&comprobar);
cout << "Como Uint8: " << hex
     << p8[0] << ' ' << p8[1] << ' ' << p8[2] << ' ' << p8[3] << endl;

> Un cordial saludo, y Steven de nuevo muchísimas gracias, cada vez
> entiendo más y mejor.
> 

De nada.


Espero que lo anterior aclare más este tema.

Steven


_______________________________________________
Lista de correo Cconclase Cconclase en listas.conclase.net
http://listas.conclase.net/mailman/listinfo/cconclase_listas.conclase.net
Bajas: http://listas.conclase.net/index.php?gid=2&mnu=FAQ



      
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <http://listas.conclase.net/pipermail/cconclase_listas.conclase.net/attachments/20110228/fe404d7b/attachment.html>


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