Jporta feladatbeadás, gyakori hibák, FAQ
Beküldte Szeberényi Imre - 2017-05-06 00.34
Otthon jól fut, de a ... Jporta nem fogadja el!
Mi az alapvető különbség a saját fejlesztőkörnyezetem és a Jporta között?
- A Jporta LINUX-on fut.
- Amennyiben az Ön fejlesztőkörnyezete Windows alapú, és a program szöveges adatfájlokat dolgoz fel, akkor gyakran okoz gondot a két rendszerben eltérő sorvégkezelés (\r \n vs. \n). Ötleteket ld. lent
- Nincs Windows specifikus interfész és header
- Egészen biztos, hogy a memóriakezelés eltérő, ezért másutt, más memóriaszemét keletkezik. Ha a programban inicializálatlan változó, terület van akkor annak tartalma biztosan el fog térni.
- Eltérőek a változók méretei
- A futtatás és fordítás batch környezetben történik. Nincs interaktív felület.
- A standard inputról várt adatokat egy szövegfájlba kel írni, és azt fel kell tölteni a Szabványos bemenet optional ponthoz. Amennyiben az inputon speciális karakterek is előfordulnak (pl. TAB), akkor ügyelni kell, hogy olyan editorral hozzuk létre a fájlt, ami kétes ilyen karaktert tárolni. Több editor a TAB-ot szóközökre cseréli!
- Ha nem tölt fel ilyet, és a program a standard inputról próbál olvasni, akkor azonnal fájl végét fog kapni. Ha ezt nem kezeli, és újból olvas (tipikus hiba), akkor végtelen ciklusba kerül a program.
- Mivel ilyenkor nem a terminálkezelőnek írjuk be az inputot, hanem közvetlenül a futó programnak, a beírt karakterek nem íródnak vissza (nincs echo). Érdemes feltételes fordítással betenni a programba, hogy a Jportan-n futva írja vissza a beolvasott szöveget.
- Az eredményt a standard kimenetre, vagy a standard hibakimenetre kell írni, melynek tartalma megjelenítésre kerül a portálon, de ennek a nagysága limitált.
- A rendelkezésre álló erőforrások limitáltak
- Limitált a használható memória mérete, és nincs megengedve minden rendszerhívás. Így pl. új processz sem indítható. A normál feladatokat ez a limitáció többnyire nem érinti. Ezzel kapcsolatban érdemes tudni, hogy system hívás új processzt indít. Azaz a system(clear) utasítás sem megengedett, ami amúgy is meglehetősen ágyúval verébre történet, ugyanis azért indít valaki új processzt, hogy letörölje a képernyőt? A memtrace.h a sysetem hívást ignorálja, de ehhez include-olni kell!
- Limitált a futási idő is.
Tipikus hibák
-
Hiba Zip fájl feltöltésekor:
The following files are not valid ZIP archives, or compression is unknown ...
hibajelzés sérült zip fájlra utal, vagy a feltöltött Zip file olyan tömörítő algoritmust használ (pl. deflate64), amit a Jporta nem tud kitömöríteni. Használjon más algoritmust (pl. deflate) a deflate64 helyett. -
Fordítási (linkelési) hiba:
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o: In function `_start':
:
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
make: *** [runnable] Error 1
A feltöltött zip nem tartalmaz olyan forrást, amiben main függvény található. Tipikus jele annak, hogy alkönyvtárba tették a forrásokat - Figyelmeztető üzenetből fordítási hiba:
cc1plus: all warnings being treated as errors
: A feladatkiírás szerint warning sem lehet a beadott kódban. Meg kell szüntetni a figyelmeztető üzeneteket. - Visszatérési érték: 120: Memóriakezelési hiba van a programban! Ha a jelenség a saját környezetben nem jön elő, akkor a következőkre kell gondolni:
- Valamiért (pl. CRLF probléma, file vége kezelés miatt) olyan ágra fut a program amin tényleg van hiba
- memtrace.h A lokális környezetben nincs használva, vagy rossz helyen van include-olva
- Inicializálatlan változó más környezetben más hatással van
- Visszatérési érték: -9 The program was killed because it was running too long.::
A program végtelen ciklusba került. A fő beolvasó ciklus nem vizsgálja az EOF lehetőségét a standard inputról. Érdemes kipróbálni a programunkat, hogy hogyan reagál indulás után egy ctrl-Z-re! - Visszatérési érték: -11:
A program olyan memóriaterülethez próbált hozzáférni, ami nem elérhető a program számára. Rosszul használt pointer vagy NULL pointer okozhat ilyet. - Bármilyen visszatérési érték, üres kimenet:
A program elszállt. Lehet, hogy írt ki valamit, de az az output stream pufferében maradt. Célszerű a pufferelést (ld. lentebb) kikapcsolni, és debug kiírásokkal behatárolni a hiba helyét. - Visszatérési érték: -31: Többnyire arra utal, hogy a kód olyan rendszerhívást használt, amit biztonsági okokból nem enged a Jporta. Ilyen pl. a system(), közvetlen device (/dev/tty) megnyitása.
Jelenleg a fájl törlés sem megengedett (int std::remove( const char* fname)). - The program produced too much output, ..... :
Valószínű végtelen ciklusban ír a standard kimenetre a program. Tipikusan nem, vagy rosszul kezeli a fájl végét. Ha elfogy az a text fájl, amit a szabványos bemenetként töltött fel, akkor file végét kap a program minden további olvasásra.
Ötletek a hibakereséshez
- Mindenképpen próbálja ki a saját környezetében, hogy programindítás után ctrl-Z -t (Linuxon ctrl-D -t) nyom! Ha program ettől végtelen ciklusba esik, akkor elsőként ezt szüntesse meg!
- Ha a program a saját környezetben jól fut, akkor valamilyen olyan hibára kell gyanakodni, ami a két rendszer közötti eltérésből adódik. Ilyen pl. a szövegfájlok CRLF problémája. Ha a saját környezete MS Windows, akkor az ilyen jellegű hibát úgy érdemes megkeresni, hogy bináris fájlmegnyitást használunk a szövegfájlokra is. Ekkor ugyanis mind a CR (\r) mind az LF (\n) karaktert megkapja a program. A probléma megoldására egy architektúra független getline-t mutat a mintafeladat (NF kesz):
namespace cp { //cross-platform getline std::istream& getline(std::istream& is, std::string& str) { std::getline(is, str); if (str.size() && *str.rbegin() == '\r') str.erase(str.size()-1); return is; } }
- Másik eltérés, hogy a Jporta 64 bites Intel architektúrán fut. Az CodeBlocks win7,8,10 környezetben is többnyire 32 bites kódot állít elő. Ez a változók méretét, értékkészletét is befolyásolja.
- A hiba behatárolását nehezíti, hogy egy távoli rendszeren kell azt megkeresni debugger nélkül. Ilyenkor nem marad más, mint nyomkövető kiírásokat tenni a kódba (ld. később), vagy a távoli környezetet kell a lokális környezetben leképezni, szimulálni. Egy ilyen megoldás található a GIT tárolóban amivel a NHF saját Linux környezetben ellenőrizhető úgy, ahogy a Jporta is ellenőrzi. A környezet a korábban megismert CIRCLE felhő rendszerben a következő lépésekkel állítható elő:
- Nyissa meg a cloud.bme.hu oldalt! Itt válassza a KIFU-NIIF nevű adatközpontot, majd lépjen be a rendszerbe EduID-azonosítójával (az eduID ikonra kattintson)! Indítson el egy virtuális gépet a "C++ labor" sablonnal, és lépjen be a gépre! Az indítás részleteit itt találja (1–6. feladatok).
- Lépjen be (ssh, putty)
- Töltse le a NHF-hez kialakított pédarpojektet!
git clone https://git.ik.bme.hu/Prog2/ell_feladat/NHF.git # navigáljon a Test katalógusba cd NHF/Test # Másolja be (scp, WinSCP) ebbe a katalógusba a feladathoz beadandó fájljait # (src.zip, adatok.zip, input.txt)! (Ne használjon szóközt, ékezetet a fájlnevekben!) # csomagolja ki a zip-eket: make unpack # fordítsa le programot: make CHK=MEMTRACE # vagy address sanitizereel: make # futtasson interaktívan: ./exe # futtasson az input átirányításával: ./exe < input.txt # ha nem tölt fel input állományt, akkor az ennek a parancsnak felel meg: ./exe < /dev/null
- Nyomkövető kiírások: Fontos tudni, hogy legtöbb futtató környezet az I/O gyorsítása érdekében mind a kimentet, mind a bemenetet puffereli. A puffer normál körülmények között automatikusan ürül pl. input esetén, illetve a program megállásakor is. Abban az esetben viszont, amikor a program abnormálisan áll le ez, nem történik meg. A hibás programok rossz szokása, hogy gyakran abnormálisan állnak le. Lehet, hogy kiírtunk egy üzenetet, de az még a pufferben van amikor a program elszáll. Mit lehet tenni?
- Minden kiírás után erőszakkal üríteni kell a puffert pl. így:
#ifdef CPORTA std::cout << "ez egy fontos kiiras" << std::endl << std::flush; // flush mint, manipulátor std::cout << "ez meg fontosabb"; std::cout.flush() // flush(), mint tagfüggvény #endif
- Másik lehetőség a pufferelés kikapcsolása pl. így:
... #include <cstdio> ... int main() { setbuf(stdout, 0); // kikapcsolja a pufferelést, ahogyan a hftest-ben is
A pufferelés kikapcsolását segíti a memtrace.h fejlécállomány: Ha a CPORTA makró definiálva van, de nincs definiálva a CPORTA_NOSETBUF makró, akkor a program indulásakor kikapcsolódik a pufferelés. Ehhez természetesen include-olni kell a memtrace.h fejlécállományt.
- Az ilyen kiírásokat érdemes feltételes fordításba tenni. Így egy mozdulattal kiszedhetők, vagy éppen visszarakhatók.
Bármelyik megoldást is választjuk, érdemes makróval vagy sablonnal segíteni a munkát segédeszközként. Pl:template <typename M> void debugMSG(std::ostream& os, M msg) { #ifdef DEBUG os << msg << std::flush; #endif // DEBUG .... // használat debugMSG(std::cout, "haho");
- Minden kiírás után erőszakkal üríteni kell a puffert pl. így:
Utolsó frissítés: 2024-05-22 12.28