Tema 1 Multi-platform Development

Dată publicare: 1 martie 2018

Deadline: 14 martie 2018, ora 23:55

Deadline hard: 21 martie 2018, ora 23:55

Scopul temei

  • Recapitularea lucrului cu funcțiile ANSI C:
    • lucrul cu fișiere
    • alocare dinamică de memorie
  • Folosirea pointerilor
  • Folosirea bibliotecilor dinamice

Dezvoltarea temei

Dezvoltarea trebuie făcută exclusiv pe mașinile virtuale SO:

Vă rugăm să parcurgeți indicațiile din cadrul secțiunii despre mașini virtuale

  • Important: folosiți 7zip pentru dezarhivarea mașinilor, este posibil să apară probleme cu alte programe de dezarhivare)

Enunț

Să se implementeze în C o tabelă de dispersie (hashtable) ce va conține cuvinte. Operațiile ce trebuie implementate pentru tabelă sunt următoarele:

Operația Descrierea operație
add <cuvânt> adaugă cuvântul la hashtable (nu se permit dubluri)
remove <cuvânt> șterge cuvântul din hashtable (nu e obligatoriu să existe cuvântul)
find <cuvânt> [<fișier_ieșire>] caută cuvântul în hashtable → scrie True sau False pe o linie nouă în fișierul specificat sau la consolă dacă acest parametru lipsește
clear golește tabela
print_bucket <index_bucket> [<fișier_ieșire>] scrie cuvintele din bucketul respectiv, pe o singură linie și separate de spațiu în fișierul specificat sau la consolă dacă acest parametru lipsește; index_bucket este valid (nu se acceptă altceva decât parametru numeric la comandă. Va trebui să verificați că argumentele sunt valide)
print [<fișier_ieșire>] printează toate bucket-urile pe linii diferite, începând cu bucketul 0, în fișierul specificat sau la consolă dacă acest parametru lipsește
resize double dublează dimensiunea hash-ului (bucket-urile vor fi parcuse în ordine și cuvintele sunt redistribuite). Pentru comanda resize va trebui să verificați că argumentele sunt valide
resize halve înjumătățește dimensiunea hash-ului (bucket-urile vor fi parcuse în ordine și cuvintele sunt redistribuite; memoria în surplus va fi dealocată). Se garantează în teste că dimensiunea hash-ului va fi mai mare sau egală cu 2 de fiecare dată când e chemată această comandă pe hashtable.

Aceste comenzi se vor regăsi una per linie.

Programul va primi o serie de parametri:

  • Primul parametru este lungimea inițială a hashtable-ului
  • Următorii parametri sunt opționali și reprezintă o listă de fișiere de intrare din care se face citirea. Dacă aceștia lipsesc citirea se face de la intrarea standard (STDIN). Atenție, în cazul în care sunt specificate mai multe fișiere de intrare, toate operațiile se aplică aceluiași hashtable, în ordinea în care au fost transmiși din linia de comandă. Dacă un fișier nu există, el este ignorat.

Exemplu:

 ./tema1 256 hash1.in hash2.in
 ./tema1 100 < hash1.in
 
hash1.in:
add tema
add hash
print hash.out
find tema hash.out
remove tema
find tema hash.out
print hash.out
resize double
print
print_bucket 185 hash2.out

Hashtable-ul implementat va conține SIZE bucketuri. Fiecare bucket va conține cuvintele în ordinea în care ele au fost introduse. Pentru operația de resize bucketurile vor fi parcurse în ordine și redistribuite. Cuvintele din bucket vor fi parcurse începând cu cel mai vechi și terminand cu cel mai recent.

Precizări generale

Indicațiile și precizările generale pentru teme sunt valabile și aici. Vă rugăm să le parcurgeți și să țineți cont de ele înainte de a vă apuca de temă și respectiv înainte de submisia finală.

  • Valorile introduse în hashtable sunt cuvinte urmând regex-ul [A-Za-z]+.
  • Un tablou NU poate conține duplicate.
  • Nu există limitări pentru lungimea unui bucket.
  • Inserarea într-un tablou (bucket) se face la finalul acestuia.
  • Antetul funcției de hash ce trebuie folosită (în întreaga temă) este declarat în hash.h. Definiția funcției se găsește într-o bibliotecă dinamică (libhash.so pentru Linux, respectiv hash.dll pentru Windows). Va trebui să linkați în tema voastră aceste biblioteci. Este interzisă folosirea unei alte funcții hash scrisă prin surse. Nu includeți bibliotecile în arhiva finală a temei.
    • IMPORTANT: bibliotecile au fost compilate folosind mașinile virtuale, care sunt cu arhitectura pe 32-bit (i686). Dacă dezvoltați pe mașina locală e posibil să vă apară erori de incompatibiltate.
  • Programul trebuie să execute comenzile în ordine, așa cum au fost primite sau citite din fișier(e).
  • Liniile goale din fișierul de intrare trebuie ignorate (programul nu face nimic și trece la linia următoare)
  • În fișiere se va scrie în modul append.
  • Dacă dimensiunea hash-ului este impară (2k+1), după înjumătațire dimensiunea lui va fi k.
  • Lungimea hash-ului și a unui cuvânt vor fi reprezentate pe un număr pe 16 de biți (fără semn).
  • Șirul vid nu este valid.
  • Dimensiunea hashtable-ului va fi întotdeauna pozitivă.
  • Funcțiile care manipulează hashtable-ul trebuie să funcționeze pe hashtable-ul primit ca parametru, nu direct pe unul care este definit ca variabilă globală. Puteți, de exemplu, pentru tema 1 să vă definiți un pointer global la un hashtable dar funcțiile trebuie explicit să primească ca parametru un hashtable, chiar dacă acesta e global.
  • Executabilul generat va purta numele tema1 pe Linux și tema1.exe pe Windows.
  • Dimensiunea maximă a unei comenzi (alcătuită din operația și cuvântul asociat) este de 20000 de caractere.
  • Buffer-ul folosit pentru citirea comenzilor poate fi declarat cu dimensiune statică.
  • Comportamentul dorit la resize este unul echivalent cu următorul: se creează un nou hash, se iterează prin bucketurile din vechiul hash și se adaugă în noul hash.
  • Hashtable-ul NU poate fi implementat folosind vectori alocați static.
  • În cazul în care un bucket este gol, NU trebuie inserată o linie goală
  • Orice eroare (inclusiv în cazul unei comenzi greșite primite în fișier sau de la stdin) trebuie raportată la stderr cu un mesaj sugestiv. Puteți folosiți macro-ul DIE. Din main() trebuie ca aplicația voastră să se întoarcă cu orice valoare mai mică decât 0 imediat ce ați întâmpinat o eroare sau un parametru invalid.

Precizări VMChecker

Arhiva temei va fi încărcată de două ori pe vmchecker (Linux și Windows). Arhiva trimisă trebuie să fie aceeași pe ambele platforme (se vor compara cele două arhive trimise).

Insistăm, dacă mesajul cu roșu nu a fost clar: arhiva care se trimite pe vmchecker trebuie să fie identică pe ambele platforme. Puteți folosi md5sum sau sha1sum (sau comenzi similare) asupra arhivelor voastre dacă ați dezvoltat în locuri diferite.

Temele trimise pe o singură platformă sau cu arhive diferite nu vor fi punctate și vor fi notate cu 0.

Arhivele trebuie să conțină sursele temei, README și două fișiere Makefile care conțin target-urile build și clean:

  • Linux: Fișierul Makefile se va numi GNUmakefile.
    • ATENȚIE: GNUmakefile (cu m mic).
  • Windows: Fișierul Makefile se va numi Makefile.
  • Regula de build trebuie să fie cea principală (executată atunci când se dă make fără parametrii)

Executabilul rezultat din operația de compilare și linking se va numi tema1 pe Linux și tema1.exe pe Windows.

Nu e nevoie să includeți bibliotecile dinamice în arhivă.

Punctare

  • Tema va fi punctată cu minimul punctajelor obținute pe cele două platforme. Nu aveți voie să folosiți directive de preprocesare de forma:
#ifdef __linux__
[...]
#ifdef _WIN32
[...]

Cu alte cuvinte: exact același cod trebuie să ruleze pe ambele platforme. Tema NU TREBUIE să conțină surse specifice unuia sau altuia dintre sistemele de operare Linux/Windows. Veți avea două fișiere makefile (GNUmakefile pentru Linux și Makefile pentru Windows, cum e precizat mai sus) iar checker-ul va ști, în funcție de sistemul lui de operare, ce makefile să folosească.

Nota mai poate fi modificată prin depunctări suplimentare:

  • -1 folosirea unei funcții proprii de hash, alta decât cea declarată în header-ul hash.h din schelet și a cărei definiție se găsește în libhash.so și hash.dll. Este deja test pe vmchecker, însă în cazul în care considerăm că a trecut din cauza unui bug în vmchecker aplicăm manual depunctarea.
  • -2 implementare netransparentă a hashtable-ului; operațiile pe hashtable nu abstractizează implementarea lui: nu există o abstractizare a obiectului hashtable sau operații clare asupra acestuia
  • -4 alocare statică hash
  • se pot scădea oricâte puncte pentru teme care conțin erori grave/vizibile de coding style sau de funcționare care pot să nu fie pe lista generală de depunctări

Testul 0 din cadrul checker-ului temei verifică automat coding style-ul surselor voastre folosind stilul de coding din kernelul Linux. Acest test valorează 5 puncte din totalul de 100. Pentru mai multe informații despre un cod de calitate citiți pagina de recomandări.

Pentru investigarea problemelor de tip Segmentation Fault sau comportament incorect al aplicației la unul din teste, pentru debugging, se recomandă folosirea gdb în Linux.

Una dintre depunctări este pentru leak-uri de memorie. În Linux pentru identificarea lor puteți folosi utilitarul valgrind.

Pentru instalarea gdb și valgrind, pe o distribuție Ubuntu se poate folosi comanda:

student@so:~$ sudo apt-get install gdb valgrind

Pentru debugging și detectarea leak-urilor de memorie este necesar să ștergeți toate optimizările de la flag-urile de compilare (e.g. -O3) și trebuie să compilați doar cu flag-urile -Wall -g (sau cele care mai activează alte warning-uri, e.g. -Wextra).

Nu trebuie la fiecare eroare considerată fatală să eliberați fiecare pointer alocat dinamic. În cadrul corecturii temei principala verificare pentru memory leaks va fi pe o funcționare corecta/normală, fără input invalid. Rețineți că memory leak-ul apare atunci când programul vostru nu poate returna sistemului de operare memoria folosită! Concentrați-vă pe folosirea valgrind pe teste care trec și care dau input valid într-o primă fază.

Precizare Makefile

Makefile-ul trebuie să respecte următoarea structură: pentru fiecare fișier .c generat trebuie să se obțină un fișier obiect. La final trebuie să faceți linkarea între sursa principală (să zicem main.c din care se obține main.o), celelalte fișiere obiect obținute din celelalte surse ale voastre și biblioteca libhash.so pe Linux, respectiv hash.dll pe Windows.

Porniți de la scheletul de Makefile atât pentru Linux cât și pentru Windows oferit în temă. Un exemplu puteți găsi aici.

Materiale ajutătoare

Semnătura funcției de hash este:

#ifndef HASH_H_
#define HASH_H_
 
unsigned int hash(const char *str, unsigned int hash_length);
 
#endif
  • Arhiva cu teste. Pe Windows testele se rulează folosind consola Cygwin. Arhivele de teste mai conțin și informații adiționale care v-ar putea ajuta.

Soluția folosită pentru generarea fișierelor de referință afișează un EOL ('\n') în plus după fiecare comandă print, print_bucket sau find. Nu este nevoie să reproduceți acest comportament întrucât testele ignoră diferențele ce constau în linii goale (se rulează comanda diff -B). A se vedea și referința la problema originală. Vă rugăm să semnalați pe lista de discuții în cazul în care testele nu țin cont de această problemă sau rezultatele voastre sunt corecte dar checker-ul nu acordă punctajul din cauza EOL sau a spațiilor goale.

Atât semnătura pentru funcția de hash, cât și testele se găsesc pe repo-ul so-assignments de pe Github. În repository-ul de pe Github se află și scheletele pentru temele viitoare, care vor fi actualizate și se vor putea descărca pe viitor folosind comanda:

student@so:~$ git pull

Tot prin comanda de mai sus se pot obține toate actualizările făcute la funcția de hash sau la testele din cadrul temei 1.

Tot în repository-ul so-assignments de pe Github se află un script Bash care vă ajută să vă creați un repository privat pe instanța de Gitlab a facultății, unde aveți la dispoziție 5 repository-uri private utile pentru teme. Urmăriți indicațiile din README și de pe wiki-ul SO.

În plus, responsabilii de teme se pot uita mai rapid pe Gitlab la temele voastre pentru a vă ajuta în cazul în care întâmpinați probleme/bug-uri. Este mai ușor să primiți suport în rezolvarea problemelor implementării voastre dacă le oferiți responsabililor de teme acces la codul sursă pe Gitlab.

Dacă ați folosit gitlab pentru realizarea temei, indicați în README link-ul către repository. Asigurați-vă că responsabilii de teme au drepturi de citire asupra repo-ului vostru.

Crash-course practic de git puteți găsi aici: git-immersion

FAQ

  • Q: Tema 1 se poate face în C++?
    • A: Nu.
  • Q: “Valorile introduse în hastable sunt cuvinte [A-Za-z]+” - trebuie verificate cuvintele la introducere?
    • A: Nu.
  • Q: Se pot folosi directive de preprocesare de tipul #define?
    • A: Da. Singurele directive de preprocesare interzise sunt cele care introduc cod condițional în funcție de OS-ul folosit (e.g. ifdef __linux__)
  • Q: Pentru citire/scriere din fișier/consolă putem folosi freopen?
    • A: Da, e ok. Puteți folosi orice funcție din categoria fopen, fread, fwrite, fclose.
  • Q: Se poate folosi realloc?
    • A: Da.
  • Q: Se pot folosi funcțiile fgets, fscanf, printf, fprintf?
    • A: Da. Atenție să nu folosiți gets!
  • Q: Pe Windows, folosind cl.exe nu mi se compilează același cod care mi se compila pe Linux. De ce?
    • A: Cel mai probabil cauza este următoarea: pe Linux este folosit C99 ca standard la gcc, care printre altele acceptă să declari variabile în mijlocul codului. Pe Windows, compilatorul cl folosește standardul C89, care forțează declararea variabilelor doar la început (un exemplu de problema).
  • Q: Văd că pentru coding style iau 0, ce pot face în această situație?
    • A: Descărcați cu wget checkpatch.pl de aici, îl puneți în PATH și apoi rulați checker-ul de Linux (pașii sunt mai jos). Alternativ, vă puteți folosi de acest wrapper peste checkpatch.pl a verifica sursele folosind criteriile considerate în evaluarea temelor.
student@so:~$ wget https://raw.githubusercontent.com/torvalds/linux/master/scripts/checkpatch.pl
student@so:~$ export PATH=$PATH:/path/to/dir/with-checkpatch
student@so:~$ cd /path/to/lin/checker && ./run_all.sh

Suport, întrebări și clarificări

Pentru întrebări sau nelămuriri legate de temă folosiți lista de discuții sau canalul de IRC.

Orice intrebare pe mailing list e recomandat să aibă subiectul de forma [Tema1][Platforma] Titlul problemei. Exemple de așa da:

  • [Tema1][Linux] Memory leaks detected, desi am facut free
  • [Tema1][Windows] No makefile found
  • [Tema1][General] Neclaritate enunt: functie hash

Exemple de așa nu:

  • Problema la tema 1
  • eroare tema 1
  • eroare la hash

Evident, și în cel de-al doilea caz veți primi răspunsuri, dar e posibil să le primiți mai greu. În conținutul emailului, în caz de probleme mai specifice dați cât mai multe detalii despre ce ați încercat, mesaje de eroare, faceți attach la log-uri de execuție, output-uri de comenzi respectiv ce comenzi ați rulat etc.

Revedeți și secțiunea de guidelines pentru lista de discuții SO

so/teme/tema-1.txt · Last modified: 2018/03/01 16:42 by mbarbulescu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0