TODOPIC

Lenguajes de programación para PC => C, C#, C++ => Mensaje iniciado por: migsantiago en 16 de Marzo de 2008, 16:02:20

Título: Validando un IF
Publicado por: migsantiago en 16 de Marzo de 2008, 16:02:20
Hola

Estaba trabajando con una instrucción if para aplicar una máscara. Primero pego el código para explicarme  :mrgreen:

Código: [Seleccionar]
#define PAD_BUTTON_A 0x0100
#define PAD_BUTTON_B 0x0200
#define PAD_TRIGGER_Z 0x0010

int buttonsdown; //variable de 32 bits que almacena los botones presionados

...
   
    //Si presiona A y B activa motor del control, buttonsdown vale 0x0300
    if((buttonsdown&(PAD_BUTTON_B|PAD_BUTTON_A))==(PAD_BUTTON_B|PAD_BUTTON_A))
        motor=1;
    //Si presiona A y Z desactiva motor del control, buttonsdown vale 0x0110
    if((buttonsdown&(PAD_TRIGGER_Z|PAD_BUTTON_A))==(PAD_TRIGGER_Z|PAD_BUTTON_A))
        motor=0;

En el código anterior si se aplica la máscara de A+B (0x0300) sobre buttonsdown (0x0300) y el resultado da 0x0300, entonces el if ejecuta su contenido, no hay problema. En caso contrario no ejecuta su contenido.

Tengo entendido que el contenido de un IF solo se ejecuta si lo que evalúa es diferente a cero, pero si reduzco el código de mi programa a lo siguiente:

Código: [Seleccionar]
if(buttonsdown&(PAD_BUTTON_B|PAD_BUTTON_A))
        motor=1;

El contenido ya no se ejecuta. Si se evalúa, el resultado que tiene el if es 0x0300, el cual es diferente a cero, pero el if no hace nada.

¿Cuál es la diferencia? No entiendo porque funciona solo si hago la comparación ==.
Título: Re: Validando un IF
Publicado por: Nocturno en 16 de Marzo de 2008, 16:08:18
¿Qué hace la función buttonsdown&?
Título: Re: Validando un IF
Publicado por: migsantiago en 16 de Marzo de 2008, 16:52:39
ah perdón, se me olvidó comentar que buttonsdown es una variable de 32 bits que almacena en cada bit un uno o un cero, dependiendo de si un botón es presionado o no.
Título: Re: Validando un IF
Publicado por: Nocturno en 16 de Marzo de 2008, 16:58:29
Pues entonces me quedo con la misma duda que tú, no veo porqué no funciona.
Título: Re: Validando un IF
Publicado por: migsantiago en 16 de Marzo de 2008, 17:05:18
Mmhhh, voy a pegar todo el código. Al principio cuando checo si solo un botón es presionado, el if funciona correctamente, pero cuando uno dos máscaras (a+b) el if ya no funciona, cosa rara  :D

Código: [Seleccionar]
//Programa que lee el estado del control 1
//controla también el motor
//san.link@yahoo.com.mx

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <ogcsys.h>
#include <gccore.h>

static void *xfb = NULL;
static GXRModeObj *rmode = NULL;

//Inicialización del video
void video_inicia()
{
VIDEO_Init();
PAD_Init();
switch(VIDEO_GetCurrentTvMode()) {
    case VI_NTSC:
            rmode = &TVNtsc480IntDf;
            break;
    case VI_PAL:
            rmode = &TVPal528IntDf;
            break;
    case VI_MPAL:
            rmode = &TVMpal480IntDf;
            break;
    default:
            rmode = &TVNtsc480IntDf;
            break;
}
xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
console_init(xfb,20,20,rmode->fbWidth,rmode->xfbHeight,rmode->fbWidth*VI_DISPLAY_PIX_SZ);
VIDEO_Configure(rmode);
VIDEO_SetNextFramebuffer(xfb);
VIDEO_SetBlack(FALSE);
VIDEO_Flush();
VIDEO_WaitVSync();
if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync();
}

//Subfunción que imprime 4 espacios
void espacios()
{
    printf("    ");
}

//Subfunción que imprime un caracter y 3 espacios
void caracter()
{
    printf("%c   ",233);
}

/////////////////////////////////////////////////////////////////////////////////////////
//Función principal
int main()
{   
//Declaro mis variables
int buttonsdown; //almacena qué botones se apretaron en el control 1
s8 stickx,sticky,c_x,c_y; //stick normal y stick c
u8 trigr,trigl; //nivel de presión de botones l y r
bool motor=0; //activa o desactiva el motor
   
//Inicia video
video_inicia();
   
//Comienza mi programa
while(1)
{
    VIDEO_WaitVSync();
    printf("\n--------------------------\n");
    printf("Sanlink\n");
    printf("Estado del control 1\n");
    printf("A + B - Activar motor\n");
    printf("A + Z - Desactivar motor\n");
   
    PAD_ScanPads();
    //lee los recién presionados y los anteriores
    buttonsdown = PAD_ButtonsDown(0)|PAD_ButtonsHeld(0);
   
    c_x=PAD_SubStickX(0);
    c_y=PAD_SubStickY(0);
   
    stickx=PAD_StickX(0);
    sticky=PAD_StickY(0);
   
    trigl=PAD_TriggerL(0);
    trigr=PAD_TriggerR(0);
   
    printf("\nBotones presionados:\n");
    printf("A   B   X   Y   Z   ST  L   R   UP  DW  LF  RT\n");
    if(buttonsdown&PAD_BUTTON_A) caracter(); else espacios();
    if(buttonsdown&PAD_BUTTON_B) caracter(); else espacios();
    if(buttonsdown&PAD_BUTTON_X) caracter(); else espacios();
    if(buttonsdown&PAD_BUTTON_Y) caracter(); else espacios();
    if(buttonsdown&PAD_TRIGGER_Z) caracter(); else espacios();
    if(buttonsdown&PAD_BUTTON_START) caracter(); else espacios();
    if(buttonsdown&PAD_TRIGGER_L) caracter(); else espacios();
    if(buttonsdown&PAD_TRIGGER_R) caracter(); else espacios();
    if(buttonsdown&PAD_BUTTON_UP) caracter(); else espacios();
    if(buttonsdown&PAD_BUTTON_DOWN) caracter(); else espacios();
    if(buttonsdown&PAD_BUTTON_LEFT) caracter(); else espacios();
    if(buttonsdown&PAD_BUTTON_RIGHT) caracter(); else espacios();
   
    printf("\n");
   
    printf("Stick   - X:%d Y:%d\n",stickx,sticky);
    printf("Stick C - X:%d Y:%d\n",c_x,c_y);
    printf("Bot R - %u\n",trigr);
    printf("Bot L - %u\n",trigl);
    printf("Motor - %d\n",motor);
    printf("Buttonsdown: %04x\n",buttonsdown);
   
    //Si presiona A y B activa motor del control
    if((buttonsdown&(PAD_BUTTON_B|PAD_BUTTON_A))==(PAD_BUTTON_B|PAD_BUTTON_A))
        motor=1;
    //Si presiona A y Z desactiva motor del control
    if((buttonsdown&(PAD_TRIGGER_Z|PAD_BUTTON_A))==(PAD_TRIGGER_Z|PAD_BUTTON_A))
        motor=0;
    if(motor)
        PAD_ControlMotor(PAD_CHAN0,PAD_MOTOR_RUMBLE);
    else
        PAD_ControlMotor(PAD_CHAN0,PAD_MOTOR_STOP);
   
    sleep(1); //espera 1 segundo para actualizar información
   
}
return(0);
}
Título: Re: Validando un IF
Publicado por: Menta en 16 de Marzo de 2008, 17:25:53
La verdad es que debería funcionar igual, tampoco sé por qué no funciona, pero me parece que al margen de eso hay un error de lógica. Para ser más claro voy a remplazar PAD_BUTTON_A y PAD_BUTTON_B por 0x100 y 0x200 respectivamente.

if((buttonsdown&(0x200|0x100))==(0x200|0x100))
        motor=1;

si los pines 8 y 9 de buttonsdown son 1 te queda if((0x300&0x300) == 0x300)  implica que es verdadero

Mientras que:

if(buttonsdown&(0x200|0x100))
        motor=1;

imaginate que solo está presionado el boton del bit 8 ==> ej buttonsdown = 0x100 (el boton A solo)

te queda       if(0x100 & 0x300)  y te daría verdadero si llegara a funcionar aunque en realidad no se presionaron los dos botones a la vez

En resumen la primera forma pregunta si se presionaron los 2 y la segunda si se presionó alguno de los 2
Título: Re: Validando un IF
Publicado por: migsantiago en 16 de Marzo de 2008, 17:35:50
Sí es cierto, solo usando buttonsdown & 0x0300 no verifica que ambos se hayan presionado, solo uno de los dos.

Pero aún así debería ejecutarse el if.

Bueno, gracias, me diste otra perspectiva del problema.
Título: Re: Validando un IF
Publicado por: Menta en 16 de Marzo de 2008, 17:47:30
Por nada.

Probé recién todas las combinaciones que se me ocurrieron con variables de distintos largos 32, 16, 8 mezcladas, incluso metiendo funciones dentro de la parte de evaluación del if y siempre funciona (con la versión 3.235 de CCS). Así que si tú puedes asegurar que los pines 8 y 9 de buttonsdown de 32 bits son unos al momento de evaluar la sentencia.
Lo único que puede ser es algún bug del compilador.  :?

Saludos.
Título: Re: Validando un IF
Publicado por: BrunoF en 16 de Marzo de 2008, 19:12:42
Hmmmm...

¿Así tampoco va, eh?

if((buttonsdown & (PAD_BUTTON_B|PAD_BUTTON_A)))

Digo porque ya va más de una vez que el compilador sin los paréntesis hasta en las partes mas obvias me hace cualquiera...

:D
Título: Re: Validando un IF
Publicado por: migsantiago en 16 de Marzo de 2008, 20:12:08
Pues no, tampoco exagerándole con los paréntesis  :D

Es un bug raro, pero no me sorprende, el compilador es de libre distirbución y está hecho por fanáticos, no por compañías súper experimentadas.  :)
Título: Re: Validando un IF
Publicado por: RICHI777 en 16 de Marzo de 2008, 21:18:13
Hola nose si el CCS lo soporta pero en ANSI C las constantes de 32 bits de deben colocar con el sufijo UL, ejemplo
Código: [Seleccionar]
#define PAD_BUTTON_A    0x0100UL
#define PAD_BUTTON_B    0x0200UL
#define PAD_TRIGGER_Z  0x0010UL
Esto fuerza al compilador a usar una constante de 32 bits, que opera directamente con el operando de 32 bits, en este caso ( buttonsdown ), creo, no lo puedo asegurar, es que en tu codigo se esta produciendo lo que se llama "integral promotion" ...
Saludos !
Título: Re: Validando un IF
Publicado por: migsantiago en 17 de Marzo de 2008, 00:47:13
Hola Richi

Probé agregando los define y el resultado fue el mismo, el problema está en la revisión del if.

Por cierto, el compilador que uso no es CCS, es un compilador gcc que funciona con un kit llamado devkitPro para compilar programas para el procesador PowerPC.
Título: Re: Validando un IF
Publicado por: RICHI777 en 17 de Marzo de 2008, 15:43:10
Hola, que raro que GCC tenga un bug de esta naturaleza  :shock:
Saludos !
Título: Re: Validando un IF
Publicado por: maunix en 17 de Marzo de 2008, 15:57:55
Hola Richi

Probé agregando los define y el resultado fue el mismo, el problema está en la revisión del if.

Por cierto, el compilador que uso no es CCS, es un compilador gcc que funciona con un kit llamado devkitPro para compilar programas para el procesador PowerPC.

Mirando rápidamente el problema y sin probar nada yo revisaría hacer un par de cosas

1) desactivar las optimizaciones del compilador
2) comenta las lineas por debajo del if, las que precisamente hacen que motor = 0

Y si tienes tiempo comentanos como te fué.

Me huele a que el compilador esté optimizando algo por algún criterio de que una condición no se dará nunca y por ende simplifica alguna línea.

Tal vez determina que el 1er if, será sobreescrito por el resultado del segundo if.





Título: Re: Validando un IF
Publicado por: migsantiago en 17 de Marzo de 2008, 18:00:54
Hola Mauricio

No sé como deshabilitar las optimizaciones del compilador. Funciona en una ventana de consola de windows, pero corre un programa llamado migw32 que simula un linux pequeño.

(http://img101.imageshack.us/img101/4242/dibujomb3.th.jpg) (http://img101.imageshack.us/my.php?image=dibujomb3.jpg)

Luego para compilar solo me pongo en el directorio de mi proyecto y le doy el comando make. Make usa un archivo makefile el cual siempre copio y pego, porque no tengo idea de cómo se edita.

Al final make genera un ejecutable, el cual corro en mi gamecube y veo todo en la tele.
Título: Re: Validando un IF
Publicado por: reiniertl en 17 de Marzo de 2008, 19:43:53
Si, resulota raro que exista un error no corregido de esa naturaleza en GCC, precisamente porque es para fanáticos es que ponen mucho empeño en hacerlo bueno, ni hablar de la cantidad de aplicaciones para LINUX que se hacen con ese compilador.

O es un problema de configuración del compilador, como te comenta maunix, o es algún problema en la lógica (no parece) o es simplemente algo que desconocemos todos y no tenemos la respuesta correcta.

Yo votaría por seguir el consejo del mono asustado, a pesar del susto suele ser muy preciso en sus recomendaciones.

Saludos
Reinier
Título: Re: Validando un IF
Publicado por: Geo en 18 de Marzo de 2008, 04:57:23
A mi esto me funciona perfectamente en MinGW:

Código: C
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. #define PAD_BUTTON_A 0x0100
  5. #define PAD_BUTTON_B 0x0200
  6.  
  7. int main() {
  8.     int buttonsdown = 0x0300;
  9.     int resultado = buttonsdown & ( PAD_BUTTON_B | PAD_BUTTON_A );
  10.     printf( "%x, %x, %x, %x\n", buttonsdown, PAD_BUTTON_A, PAD_BUTTON_B, resultado );
  11.  
  12.     if ( buttonsdown & ( PAD_BUTTON_B | PAD_BUTTON_A ) ) {
  13.         printf( "Sip\n" );
  14.     }
  15.     else {
  16.         printf( "Nop\n" );
  17.     }
  18.  
  19.     system( "pause" );
  20.     return 0;
  21. }

La salida del programa es:
300, 100, 200, 300
Sip
Presione una tecla para continuar...

Yo verificaría el valor de buttonsdown antes de evaluar el if.
Título: Re: Validando un IF
Publicado por: migsantiago en 18 de Marzo de 2008, 11:55:26
Hola Geo

Funciona bien, pero como comentaba Menta unos mensajes arriba, si solo se presiona B...

buttonsdown & ( PAD_BUTTON_B | PAD_BUTTON_A ) daría como resultado 0x0200, el cual de todas formas validaría el if.

Pero ya no estoy preocupado por ahora, ya dejé en el pasado este bug.  :mrgreen:

Gracias.
Título: Re: Validando un IF
Publicado por: maunix en 19 de Marzo de 2008, 15:10:24
Pero ya no estoy preocupado por ahora, ya dejé en el pasado este bug.  :mrgreen:

Pero en el caso de GEO creo que ha probado todas las posibilidades, al menos eso es lo que leo de su salida (300, 100, 200)

En cuanto a lo de bug, habría que ver, por eso te mencioné lo de las opciones de compilador.

El GCC en modo de comandos tiene posibilidad de que se le pase como parámetro el nivel de optimización, tal vez por default es máximo pero bien podrías pasarle que lo desactive.

El código que puso Geo no es idéntico al tuyo, ya que ha eliminado algunas cosas, lo cual podría afectar la labor del compilador.

Si tienes ganas de seguir probando, prueba de agregarle "volatile" antes de int buttonsdown.

Quedaría así su declaración


volatile int buttonsdown


Título: Re: Validando un IF
Publicado por: migsantiago en 19 de Marzo de 2008, 16:50:15
Sí es cierto, Richi en otro tema me comentó que poniéndole Volatile se elimina la optimización. Lo voy a probar y te comento los resultados Mauricio.  8)
Título: Re: Validando un IF
Publicado por: maunix en 20 de Marzo de 2008, 16:49:08
Sí es cierto, Richi en otro tema me comentó que poniéndole Volatile se elimina la optimización. Lo voy a probar y te comento los resultados Mauricio.  8)

Mmm, técnicamente no es que se elimina la optimización del código, solo que el compilador tiene presente que la variable en cuestión puede ser modificada por el bucle en cuestión o por otro, en una forma que no puede ser analizada por el análisis líneal del código.

Por ende tiene más cuidado con el tratamiento de la variable en cuestión en todas las partes del código donde se la use, lo cual no significa que el resto de l código no quede optimizado.
Título: Re: Validando un IF
Publicado por: migsantiago en 20 de Marzo de 2008, 21:08:16
¿Qué crees Mauricio? Que no funcionó tampoco  :cry:

Le puse volatile y el resultado fue el mismo. El código involucrado es

Código: [Seleccionar]
    //Si presiona A y B activa motor del control
    if(buttonsdown&(PAD_BUTTON_B|PAD_BUTTON_A))
        motor=1;
    //Si presiona A y Z desactiva motor del control
    if(buttonsdown&(PAD_TRIGGER_Z|PAD_BUTTON_A))
        motor=0;

Pero desde los programas anteriores noté un detalle raro con el código de arriba...

- Presiona A+B no pone a 1 el motor
- Presiona B pone a 1 el motor
- Presiona A pone a 0 el motor
- Presiona Z pone a 0 el motor

Un comportamiento sumamente raro.

Pero todo funciona al 100% si uso:

Código: [Seleccionar]
    //Si presiona A y B activa motor del control
    if((buttonsdown&(PAD_BUTTON_B|PAD_BUTTON_A))==(PAD_BUTTON_B|PAD_BUTTON_A))
            motor=1;
    //Si presiona A y Z desactiva motor del control
    if((buttonsdown&(PAD_TRIGGER_Z|PAD_BUTTON_A))==(PAD_TRIGGER_Z|PAD_BUTTON_A))
            motor=0;

Declaro la guerra contra el if ganada por los bits raros del compilador GCC  :D de ahora en adelante seré más específico en mis sentencias  8)
Título: Re: Validando un IF
Publicado por: ma4826 en 20 de Marzo de 2008, 23:21:12
De la primera forma el primer if se activa si pulsas A o B y el segundo si pulsas A o Z.

Si pulsas A+B -> Primer if pone motor = 1, el segundo if pone motor = 0, resultado final motor = 0;
Si pulsas B -> Primer if pone motor = 1, el segundo if no hace nada, resultado final motor = 1;
Si pulsas A -> Primer if pone motor = 1, el segundo if pone motor = 0, resultado final motor = 0;
Si pulsas Z -> Primer if no hace nada, el segundo if pone motor = 0, resultado final motor = 0;

Con la segunda opción el primer if se activa solo cuando pulsas A y B a la vez y el segundo cuando pulsas A y Z a la vez.

Está funcionando como debe.

Saludos,

Miguel Angel.
Título: Re: Validando un IF
Publicado por: migsantiago en 21 de Marzo de 2008, 00:52:32
 :shock:
 :D
 :oops: :oops:

Pero como no lo razoné antes... Miguel Angel, has resuelto el enigma de los $64,000.00  :D

Qué bien, gracias por analizarlo, de veras que me equivoqué y feo  :D  :g) nunca se me ocurrió analizarlo secuencialmente, solo veía a los if's como si estuvieran solos.

Ahora exonero al GCC de cualquier culpa y aprendí algo nuevo el día de hoy.  :P
Título: Re: Validando un IF
Publicado por: Nocturno en 21 de Marzo de 2008, 02:47:32
Grandísima lección que nos has dado a todos los que nos habíamos obcecado en verlo de otra manera.
Y lo peor de todo es que yo he cometido alguna vez ese mismo error en otras circunstancias y no había caído.
Título: Re: Validando un IF
Publicado por: RICHI777 en 21 de Marzo de 2008, 13:11:25
Un aplauso para Ma4826   :lol:
Como decia un viejo amigo mio...."Que el arbol nunca tape al bosque"...
Saludos !
Título: Re: Validando un IF
Publicado por: Geo en 21 de Marzo de 2008, 21:56:44
Je, nos quedamos con la primer parte :P.