Olen koodannut täällä yliopistolla ollessani mikrotyöstörobotille koordinaattiohjelmaa. Tuossa muutama päivä sitten tuli vastaan mielenkiintoinen härö ohjelman tulosteessa.
Syötetiedoston jokainen rivi kirjoitetaan tiedostoon seuraavalla koodilla:
char line[512]; ... sprintf(line, "%li;%li;%i;%i;%i\n", cx, cy, (int)(hp->depth * depth), (int)((double)workspeed * hp->speed), mode); fputs(line, output);
Kaikki muuttujat ovat kunnossa ja oikeassa muodossa (long int jne.).
Noin 180 000 rivin tulosteessa esiintyi kuitenkin yksi hyvin mystinen rivi jossa rivin ensimmäinen kokonaisluku oli 'venynyt'; rivin olisi kuulunut olla seuraava:
263680;12920;10;400;0
Rivi oli kuitenkin seuraavassa muodossa:
26************************80;12920;10;400;0
missä * tarkoittaa satunnaista merkkiä. Ilmeisesti sprintf-funktiossa tapahtuu jotain mutta mitään virhettä ei ilmoiteta ja sprintf antaa normaalin palautusarvon (5).
Onko mitään hajua miten tätä ongelmaa kannattaisi lähestyä? Toistaiseksi en ole saanut ongelmaa toistettua, mutta pelkään että JOS se toistuu siitä saattaa koitua ongelmia.
Kääntäjänä gcc, ohjelmoin Windows-ympäristössä.
Korj: otsikossa tpyo. Piti olla sprintf.
Korjattu. ~Naapurin ystävällinen moderaattori.
Muotoilufunktiossa tuskin on vikaa, ja nykykoneilla myös hetkellinen laitteistohäiriö vaikuttaa aika epätodennäköiseltä. Jos koodi on todella noin yksinkertainen, siinäkään ei ole vikaa (ellet käytä säikeitä ja jotenkin sotke niillä juuri tuota muistialuetta).
Onko mahdollista, että on sattunut jokin muu inhimillinen erehdys, esimerkiksi tahaton copy-paste?
Muuten, mikset tulosta suoraan fprintf-funktiolla?
Metabolix kirjoitti:
Muuten, mikset tulosta suoraan fprintf-funktiolla?
Riviä tarvitaan varmaan muuallakin?
sqwiik kirjoitti:
Onko mitään hajua miten tätä ongelmaa kannattaisi lähestyä? Toistaiseksi en ole saanut ongelmaa toistettua, mutta pelkään että JOS se toistuu siitä saattaa koitua ongelmia.
No tuossa koodissasi minkä pastetit, ei mitään vikaa näy. Vähän enemmän tartteis tietää, että osaa lähteä hakemaan vikaa. Jos olet saanut virheen tasan kerran esiin, etkä toistettua enää sen jälkeen, niin vähän kuulostaisi siltä mitä Metabolix ehdotti. Eli olet vahingossa kämmännyt jotain tuloksia tutkiessa tjms.
Oletetaan nyt että niin ei ole käynyt. Silloin vika voisi olla jossain ajoitusongelmassa (keskeytys sopivassa kohtaa), joka saisi sprintf:n oman sisäisen puskurin tai kirjoituspuskurin sekoamaan. Oletko varma että vika esiintyy juuri sprintf:n kirjoituksessa, eikä vaikkapa tuossa fputsissa? Jos onnistut sitä vikaa vielä kaivamaan esiin, niin voisit kokeilla assertteja. Niillä voisit varmistua missä rajoissa muuttujat liikkuvat kullakin hetkellä.
sqwiik kirjoitti:
Kääntäjänä gcc, ohjelmoin Windows-ympäristössä.
Onko windows myös targettina, vai ohjelmoitko jollekin mikrokontrollerille tai vastaavalle? Meneekö tuo output tiedostoon?
sqwiik kirjoitti:
sprintf antaa normaalin palautusarvon (5)
Hmm. Eikö normaali palautusarvo pitäisi olla 21? Eli kirjoitettujen merkkien määrä poislukien \0. Vai olenko vain ymmärtänyt jotenkin väärin?
c standardi kirjoitti:
The sprintf function returns the number of characters written in the array, not
counting the terminating null character, or a negative value if an encoding error occurred.
Vähän tarkennusta tähän. En ole toistaiseksi vieläkään onnistunut toistamaan ongelmaa useamman miljardin rivin tulosteilla niin kyseessä lienee ollut jokin tahatan muistikilahdus kesken sprintf-funktion suorituksen. Bhah.
No, muokkaamaan ei enää aloitusviestiä kykene niin:
Metabolix kirjoitti:
Muotoilufunktiossa tuskin on vikaa, ja nykykoneilla myös hetkellinen laitteistohäiriö vaikuttaa aika epätodennäköiseltä. Jos koodi on todella noin yksinkertainen, siinäkään ei ole vikaa (ellet käytä säikeitä ja jotenkin sotke niillä juuri tuota muistialuetta).
Onko mahdollista, että on sattunut jokin muu inhimillinen erehdys, esimerkiksi tahaton copy-paste?
Muuten, mikset tulosta suoraan fprintf-funktiolla?
Säikeitä en ohjelmassa käytä ja koodin oikeellisuus on rassattu kyllä kuntoon kun kirjoitusosion koodia ei ole copypastella otettu mistään.
fprintf on yleensä käytössä mutta tuossa on vielä kirjoituksen jälkeen yksi varmistus joka tarkistaa että homma pelaa vielä (linkitetty lista, tiedosto auki jne.) joten jos tapahtuu virhe, viimeinen kirjoitettu rivi arvoineen on vielä muistissa line-taulukossa joka näytetään sitten virhe-ilmoituksen yhteydessä. Auttaa kummasti aina välillä.
Torgo kirjoitti:
Hmm. Eikö normaali palautusarvo pitäisi olla 21? Eli kirjoitettujen merkkien määrä poislukien \0. Vai olenko vain ymmärtänyt jotenkin väärin?
Jees, oikeass aolet. Sotkin palautusarvon *scanf-funktioiden palautusarvon kanssa tuota viestiä kirjoittaessa.
Torgo kirjoitti:
Onko windows myös targettina, vai ohjelmoitko jollekin mikrokontrollerille tai vastaavalle? Meneekö tuo output tiedostoon?
Wintoosaanpa hyvinkin, olisi pitänyt muistaa mainita. Ähh.
Enempää tavaraa on tuosta koodista hyvin hankalaa antaa näkyville kun kirjoitusta ennen tapahtuu ainoastaan koordinaattien cx ja cy hienosäätö ohjausparametrien mukaan.
Ongelma on toistaiseksi siis Jäädytetyssä tilassa - sitä ei olla kyetty toistamaan eikä kirjoituskohtaa ympäröivässä koodissa ole virheitä. Joskus koodarin arki on kyllä kamalaa kuraa...
sqwiik kirjoitti:
Vähän tarkennusta tähän. En ole toistaiseksi vieläkään onnistunut toistamaan ongelmaa useamman miljardin rivin tulosteilla niin kyseessä lienee ollut jokin tahatan muistikilahdus kesken sprintf-funktion suorituksen.
Mahdollinen satunnainen muistivirhe voi myös olla tuon taustalla, kuten itsekin totesit. Normaaleissa työpöytäkoneissa, joissa ei käytetä virheentunnistavaa tai -korjaava muistia tyypillinen satunnaisten muistivirheiden (dynaamisessa RAMissa) todennäköisyys on luokkaa 1 virhe / 1Gbit / vrk. Tämä siis transienttien vikojen suhteen. Todennäköisyys pysyville muistivirheille on arviolta 100-1000 kertaa pienempi.
Aihe on jo aika vanha, joten et voi enää vastata siihen.