Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: Funktiokutsu kaataa ohjelman

Sivun loppuun

ByteMan [05.11.2009 22:53:15]

#

Ongelman ydin on siis se, että minulla on pätkä koodia, josta kutsutaan funktiota, jolloin ohjelma kaatuu:

if(SDL_PollEvent(&e)){
            nappi = SDL_GetKeyState(0);
            if(e.type == SDL_KEYDOWN){
            if(nappi[SDLK_INSERT]){
                SDL_PumpEvents();//tiedän, turha(?)
                fprintf(stdout, "moi0");//tämä ei tulostu
                al2 = relocate(al2);
            }
//*****************
alue relocate(alue pre){//relocate-funktion runko
    fprintf(stdout, "moi1"); //ei tulostu
    int lkm = 0;//klikkien määrä
    int h, x, y;
    double x1, x2, y1, y2;
    while(lkm < 2){
        h = SDL_GetMouseState(&x, &y);
        if( (lkm == 1) && ( h & SDL_BUTTON(1) ) ){
            x2 = pre.xmin + ( x * pre.xdot );
            y2 = pre.ymin + ( y * pre.ydot );
            fprintf(stdout, "moi2");//ei tulostu
            SDL_Delay(500);
            lkm++;
        }
        if( (lkm == 0) && ( h & SDL_BUTTON(1) ) ){//"väärä" järjestys
            x1 = pre.xmin + ( x * pre.xdot );     //tarkoituksella
            y1 = pre.ymin + ( y * pre.ydot );
            SDL_Delay(500);//debuggingin takia, muuten turha
            lkm++;
        }
    }
    //ongelman kannalta turhaa koodia
    return pre;
}

tosin pelkkä näppäimen painallus saattaa olla syynä, koska "moi0" ei tulostu.
Jos joku keksii missä vika niin hyvä, olen tahkonnut tätä nyt sen muutaman päivän ja alkaa omat ideat olla käytetty loppuun..
siltä varalta että asiaan mitenkään vaikuttaa tuo salaperäinen 'alue' niin sen määrittely(toivottavasti se nyt sit ol oikea sana..) näyttää tältä:

struct alue{
    double xmin;
    double xmax;
    double ymin;
    double ymax;
    double xdot;
    double ydot;
};

Kiitän jo etukäteen.

Jaska [05.11.2009 23:21:23]

#

Eikös fprintf:lle pidä antaa parametrina tiedosto, johon tulostetaan? Tulee käyttää osoitinta FILEeen tai fopen()-funktion paluuarvoa. Siis

FILE *fp;
if ((fp=fopen("tdsto", "a+"))!=NULL) {
  fprintf(stdout,"moi1");
}

ByteMan [05.11.2009 23:26:29]

#

No koska se kerran toimii kaikilla muilla näppäinpainalluksilla niin oletan että SDL alustaa sen automaagisesti ;)
...se tosin ei vielä kerro mitään mutta eipä sitä yhdessäkään SDL-koodivinkissä tai -oppaassa nähdäkseni alustettu niin sekin on ihan hyvä peruste väitteelleni.

vehkis91 [05.11.2009 23:32:15]

#

Olisiko ongelma tuossa: nappi = SDL_GetKeyState(0); käsittääkseni, se pitää tehdä vain kerran ennen pääsilmukkaa.

Edit: ja tuo SDL_PumpEvents(), on tosiaan ihan turha.

Jaska [05.11.2009 23:39:11]

#

Mutta funktiossa relocate ei ole alustuskoodia, vaan kutsutaan suoraan fprintf:ää. Standardinmukainen fprintf on määritelty ihan C:n standardissa, eli ei siihen SDL:ää tarvita. En sitten tiedä, onko SDL korvannut funktion omalla funktiolla.

Oma lähteeni on Pratan C Primer Plus

ByteMan [05.11.2009 23:45:33]

#

@vehkis:: Epäilen, sillä kaikki muut näppäimet kyllä toimivat oikein.
Kokeilin kuitenkin ja osuin oletuksessani oikeaan: vika ei ollut siinä.
@jaska:: koska asia toimii noin, niin oletan että SDL alustaa parametrin stdout, koska kun tuolla tavoin tulostelee niin tuloksena on stdout.txt tai vaihtoehtoisesti stderr.txt, tiippuen kumpaa parametria käyttää

vehkis91 [05.11.2009 23:57:03]

#

Mitäs toi al2 sisältää, ennen tuota funktiokutsua?

edit: Jökkääkö toi vasta kun painat hiiren nappia, vai heti sen jälkeen, kun painat enteriä?

ByteMan [06.11.2009 00:07:43]

#

al2 sisältää alkuarvot xmin = -2, xmax = 1, ymin = -1 ja ymax = 1
jokkää heti ku painaa nappia, oli siinä sitte insert, enter tai up
edit: nii ja xdot ja ydot sisältää "kuvasuhteen"

vehkis91 [06.11.2009 00:32:17]

#

Mitä tapahtuu jos kommentoit pois tuon alemman if? tai koko while silmukan?

Metabolix [06.11.2009 08:52:53]

#

Debuggaustavassasi on virhe: Standardivirta stdout on puskuroitu niin, että data tulostuu vasta rivinvaihdon jälkeen. Jokaisessa tulostuksessa pitäisi siis olla lopussa rivinvaihto. Parempi debug-virta olisi stderr. Jos käytät Windowsia, muista myös, että SDL saattaa ohjata standarditulosteen tiedostoon. (Edit. Muistitkin tämän jo.) Standardivirtaan tulostaessa ei tarvitse käyttää fprintf:ää, vaan printf tulostaa aina stdoutiin.

ByteMan [06.11.2009 17:11:59]

#

Korjailin vähän tuota debuggailuani, jolloin sain selville, että silloin kun tuon hiiren sijainnin ja arvojen lukemisesn laittaa lkm:n kanssa whilen ehtoon niin ohjelma EI kaadu

while( lkm < 2 && h = SDL_GetMouseState( &x, &y ){
        fprintf(stderr, "moi_while\n");

        fprintf(stderr, "moi_before_if\n");
        if( (lkm == 1) && ( h & SDL_BUTTON(1) ) ){
            x2 = pre.xmin + ( x * pre.xdot );
            y2 = pre.ymin + ( y * pre.ydot );
            fprintf(stderr, "moi3 %d %d", x1, x2);
            lkm++;
        }

tämä taas puolestaan ei toiminut oikein, koska pääohjelmassa määrättyä painiketta painaessa piti myös hiiren nappulaa painaa jotta edes päästäisiin whileen sisälle. myöskin noiden arvojen tuloste todistaa häikän:

x2 = 858993460
y2 = -1075563725

ja tässä siis tosiaan liikutaan välillä -2 <= x <= 1 ja -1 <= y <= 1

edit:: ei toiminut oikein eikä varsinkaan niinkuin piti -.-
edit2:: eli jos tuon hiiren käsittelyn laittaa tuonne silmukkaan sisälle niin ohjelma kaatu, teenkö sen jotenkin väärin?

Metabolix [06.11.2009 17:52:25]

#

Mitä tarkoitat kaatumisella? (Pitäisi varmaan kirjoittaa opas, jossa kerrottaisiin, mitä sanat tarkoittavat...)

Koodin perusteella veikkaan, että ohjelma jumittuu. Syykin on selvä: silmukasta puuttuu SDL_PumpEvents, joten hiiren tila ei muutu. Tämän lisäksi monta muutakin asiaa on päin honkia tai vähintäänkin purukumia. Pahoittelen seuraavan tekstin mahdollisesti rankkaa sävyä. :)

SDL_PumpEvents muuntaa käyttöjärjestelmän viestit SDL:n sisäiseen muotoon ja päivittää mm. hiiren ja näppäimistön tilan (SDL_GetKeyState ja SDL_GetMouseState). Viestit jäävät viestipuskuriin odottamaan käsittelyä (tosin jonolla on maksimikoko, jonka jälkeen tapahtumat vain heitetään pois).

SDL_PollEvent ja SDL_WaitEvent hakevat jonosta tapahtuman, jälkimmäinen odottaa, että saa haettavaa. Kummatkin kutsuvat sisäisesti SDL_PumpEvents-funktiota, joka hoitaa sen varsinaisen hakemisen.

Haet PollEvent-funktiolla klikkauksen, joten lue koordinaatit tapahtumasta (e.button.x, e.button.y) äläkä nykytilanteesta. SDL_PumpEvents on typerässä paikassa, koska eihän tuolla ole tarpeen päivittää SDL:n tapahtumajonoa. Se kuuluisi sijoittaa tuohon seuraavaa klikkausta odottavaan silmukkaan relocate-funktiossa. Toisaalta on tyhmää tuhlata while-silmukassa tehoa vain odottamiseen, kun voisit aivan hyvin odottaa klikkausta SDL_WaitEvent-funktiolla, jolloin ohjelma nukkuu ylimääräisen ajan. Pääsisit myös järkevämpään tulokseen, koska saisit varmasti erillisiä klikkauksia, joiden välillä sormi on taatusti ehtinyt nousta hiiren napilta.

while (peli_kaynnissa) {
  // Käsitellään KAIKKI jonossa olevat viestit.
  while (SDL_PollEvent(&e)) {
    if (e.type = SDL_MOUSEBUTTONDOWN) {
      al2 = relocate(al2);
    }
  }
  // muut jutut...
}

// ...
alue relocate(alue pre) {
  for (int lkm = 0; lkm < 2; ++lkm) {
    SDL_Event e;
    bool odota = true;
    #ifdef WAIT_EVENT_VAIHTOEHTO
      // Käsitellään KAIKKI jonossa olevat viestit, kunnes saadaan
      // napinpainallus.
      while (SDL_WaitEvent(&e) && odota) {
        if (e.type != SDL_MOUSEBUTTONDOWN || e.button.button != SDL_BUTTON_LEFT) continue;
        // Seuraava painallus tuli kohtaan (e.button.x, e.button.y).
        odota = false;
      }
      if (odota) throw "Virhe viestin odottamisessa!";
    #else
      // Toinen vaihtoehto: odotellaan nimenomaan napinpainallusta,
      // jätetään muut tapahtumat jonoon tulevaisuutta varten.
      while (odota) {
        SDL_PumpEvents();
        switch (SDL_PeepEvents(&e, 1, SDL_GETEVENT, SDL_MOUSEBUTTONDOWNMASK)) {
          case -1: throw "Virhe!";
          case 0: SDL_Sleep(10);
          case 1: if (e.button.button == SDL_BUTTON_LEFT) {
            // Tuli vasen nappi!
            odota = false;
          }
        }
      }
    #endif
  }
  return pre;
}

(Jokunen muokkaus tuli jälkikäteen.)
(Korjattu e.button => e.button.button.)

ByteMan [06.11.2009 19:36:17]

#

Mitä rankkaa sävyä? =o siinähän on vain todettu asiat niinkuin ne on ;)
Ja ihan hyvä, koska en olisi esimerkiksi tiennyt tuota e.button.x juttua, koska en ole siihen ikinä missään törmännyt.
Otin tuon ylemmän version käyttöön näin aluksi ja tutkin tuota jälkimmäistä vaihtoehtoa myöhemmin.
kääntäjä kertoi että e.buttonia ei voi vertailla != - operaattorilla(jos nyt edes tämä termi meni oikein.. =D ) joten kommentoin sen pois: ohjelman kannalta on aivan sama millä namikalla klikkaillaan kunhan klikkaillaan. Hyvä kuitenkin tietää nuokin asiat hiiren käsittelystä =)

Ja kannatan tuota opasideaasi, esimerkiksi olen jostain syystä käsittänyt että se että ohjelma ei vastaa ja että se kaatuu olisivat jotenkin sama asia..

Mutta kiitos ja kumarrus Metabolixille, sain toimimaan, nyt ainoat virheet johtuvatkin enää epätarkasta hiirikädestä ;)

Metabolix [06.11.2009 19:50:58]

#

Huppista, vertailussa piti siis olla e.button.button, joka sisältää painetun näppäimen; e.button on rakenne koko klikkaustapahtuman tiedoista. (Korjasin virheen. En sattumoisin testannut koodia, koska se on vain pieni pala ohjelmaasi.) Tuollahan on merkitystä vain, jos haluat hyväksyä vain tietyn napin klikkauksen. Jälkimmäinen tapa on jo melkoista ekstriimiä, ja en äkkiseltään keksi kovin hyvää esimerkkiä tilanteesta, jossa se edes olisi tarpeen.

Kaatumisella yleensä tarkoitetaan, että ohjelma sammuu virheen vuoksi (Windowsissa esim. "Ohjelma on suorittanut laittoman toiminnon jne...", tai ohjelma voi itse havaita virheensä ja ilmoittaa jotain vastaavaa). Sen sijaan tätä tilannetta pitäisi selkeyden vuoksi kutsua vaikka jumittumiseksi.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta