Laborator 1

Scrie un program C, care foloseste parametrii din linia de comanda. Compileaza si executa din linia de comanda.

#include <stdio.h>

#include <stdlib.h>

int main(int argc, char *argv[])

{

printf("Hello world!\n");

int i,n;

float s=0;

if(argc==0)

printf("s=0");

else

{

for(i=1;i<argc;i++)

s=s+atof(argv[i]);

printf("s=%f",s);

}

return 0;

}

gcc -Wall -o numeProgram numeProgram.c

./numeProgram 1 2

Program luat din Tehnici de programare-laborator 3

Informatii:

Comenzi Unix

UNIX are un sistem de fişiere arborescent. Spre deosebire de sistemul de fisiere DOS/Windows, separatorul între componentele numelui de fişier (directoare şi numele propriu-zis) este caracterul / (slash) şi nu \ (backslash). De asemenea, numele de fişiere nu conţin un identificator al discului fizic (A:, C:, etc.), ci întreaga ierarhie de fişiere porneşte de la o rădăcină unică, notată /. În continuare, numele comenzilor sunt scrise cu caractere tip maşină de scris, argumentele lor sunt scrise cursiv, iar textul între [ ] denotă un argument opţional. Cîteva comenzi de bază sunt:

    • mkdir nume_director

    • Creează un director (directory) cu numele dat.

    • cd [nume_director]

    • Schimbă directorul curent, trecînd in cel specificat (implicit: în directorul personal (home directory) al utilizatorului). La fel ca şi sub DOS/Windows, . denotă directorul curent, iar .. directorul părinte. Notaţia ~ se referă la directorul personal al utilizatorului curent.

    • ls [nume_catalog]

    • Listează (afişează numele pentru) fişierele din directorul dat (implicit: directorul curent).

    • cat fişier

    • Afişează conţinutul fişierului

    • cp [opţiuni] fişier1 fişier2

    • Face o copie a lui fişier1, cu numele fişier2

    • cp [opţiuni] fişier1 fişier2 fişier_n dir

    • Copiază fisierele indicate în directorul dir.

    • Opţiuni: -i (interactiv): întreabă înainte de a suprascrie; -r (recursiv, folosit): copiază toate fişierele şi subdirectoarele din directorul sursă indicat.

    • mv [optiuni] fişier1 fişier2

    • Redenumeşte fişier1, cu numele fişier2

    • mv [opţiuni] fişier1 fişier2 fişier_n dir

    • Mută fişierele indicate în directorul dir.

    • Opţiuni: -i (interactiv): întreabă înainte de a suprascrie. (Un catalog e mutat implicit împreună cu întreg conţinutul, deci opţiunea -r nu mai apare, spre deosebire de copiere)

    • rm [opţiuni] nume_fisier

    • şterge fişierul specificat. Opţiunea -i (interactiv) solicită confirmare, -f forţează (fără confirmare) iar -r şterge recursiv tot conţinutul directorului indicat.

    • rmdir nume_director

    • şterge directorul indicat (acesta trebuie să fie gol).

    • man nume_comandă/apel sistem/funcţie de bibliotecă

    • Afişează pagina de manual pentru comanda indicată (cu toate opţiunile).

Pentru o navigare şi manipulare mai facilă a fişierelor se poate folosi programul Midnight Commander (mc), similar lui Norton Commander/Total Commander din mediul DOS/Windows.

Compilatorul gcc

Compilatorul gcc (GNU Compiler Collection) este unul din cele mai performante compilatoare pentru limbajul C, şi e realizat în acelaşi model de distribuţie gratuită a sursei ca şi celelalte componente ale sistemului GNU/Linux.

Fişierele sursă au în mod convenţional extensia .c. Obişnuit, pentru a compila programul nume.c, se execută comanda

gcc -o nume nume.c

Argumentul nume al opţiunii -o indică numele dat executabilului (de obicei, acelaşi nume de bază ca şi pentru sursă dar nu neapărat). Dacă nu se foloseşte opţiunea -o nume, executabilul e denumit implicit a.out. [În UNIX, fişierele executabile nu sunt identificate prin extensie (cum ar fi .exe), ci printr-un atribut (permisiune de execuţie) care în acest caz e setat automat de compilator].

Pentru a compila programe cu funcţii matematice standard e nevoie de biblioteca libm. În acest caz, se foloseşte opţiunea -l urmată, fără spaţiu, de numele bibliotecii (fără prefixul lib folosit convenţional pentru toate bibliotecile). De exemplu:

gcc -lm -o prog prog.c

La fel atunci cînd folosim fire de excuţie pthreads avem nevoie de biblioteca libpthread, deci vom adăuga opţiunea -lpthread.

La compilare, e utila generarea cat mai multor avertismente. Aceasta se specifica cu optiunea -Wall (warnings: all).

Opţiunile la compilare pot fi introduse în orice ordine. E important de înţeles că -o nume e o singură opţiune, chiar dacă e formată din două cuvinte separate prin spaţii. E incorectă intercalarea altor opţiuni între -o şi nume. De exemplu, în comanda

gcc -o -Wall nume nume.c

se interpretează -Wall ca nume dorit al fişierului de ieşire.

Alte opţiuni pentru gcc vor fi discutate ulterior.

Erori de compilare

Pentru început, scrieţi şi compilaţi următorul program simplu, care afişează faloarea lui pi calculată cu ajutorul funcţiei arcsinus, prezentă cu numele asin în biblioteca standard de funcţii matematice.

#include <math.h> #include <stdio.h> int main(void) { printf("Valoarea lui pi este: "); printf("%f", 2 * asin(1)); return 0; }

E important să urmărim cu atenţie şi să înţelegem eventualele mesaje de apărute la compilare, pentru a putea corecta erorile semnalate. Cîteva exemple de erori care pot apărea la transcrierea greşită a acestui program:

error: studio.h: No such file or directory

Compilatorul nu a găsit fişierul indicat, deoarece a fost scris cu nume eronat: nu este studio.h, ci stdio.h, de la Standard Input/Output.

error: syntax error before 'return'

Acest mesaj va apare dacă uităm să terminăm linia anterioară cu punct-virgulă. E important de reţinut că adesea cauza reală a erorii poate să se afle de fapt puţin înainte de locul în care o detectează compilatorul. Acesta indică locul presupusei erori prin numele de fişier urmat de numărul liniei sursă, de exemplu: /home/student/pi.c:8:error: ...

error: syntax error at end of input

Această eroare va fi semnalată dacă se uită acoloada închisă } şi deci fişierul se termină în mod neaşteptat.

Rularea programelor și linia de comandă

Fie următorul program, să-l numim myecho.c:

#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int i; for (i=1; i<argc; i++) printf("Argumentul %d este: %s\n", i, argv[i]); exit(0); }

Să presupunem că am compilat în diretorul curent programul myecho.c, folosind comanda:

gcc -o myecho myecho.c

Cum lansăm această comandă în execuție? Vom utiliza următoarea linie de comandă:

./myecho arg1 arg2 arg3 gata

Să analizăm această linie (notăm cu simbolul ◊ un caracter spațiu):

./myecho◊arg1◊arg2◊arg3◊gata

  • ./

    • Reprezintă calea către fișierul myecho. Punctul reprezintă directorul curent iar bara oblică (slash) reprezintă despărțitorul de cale. Pentru ce avem nevoie de această construcție ciudată? Explicația o găsiți la secțiunea Variabila de mediu PATH.

  • myecho

    • Este numele fișierului executabil. Împreună cu calea, reprezintă primul element din linia de comandă și anume, în cazul de față, comanda ce trebuie executată.

    • Spațiul este, pentru interpretorul de comenzi, un despărțitor. El separă linia de comandă în elemente. Primul element poate fi o comandă (o cale către un fișier executabil sau un nume, vezi mai jos) sau o declarație de variabilă de mediu.

      • Fiți cu băgare de seamă: un spațiu prost plasat va sparge linia de comandă în elemente acolo unde nu doriți. Pentru ca un element să conțină spațiu (și alte caractere speciale), trebuie utilizat un mecanism de citare.

    • arg1◊arg2◊arg3◊gata

      • În cazul în care primul element e o comandă, urmatoarele elemente reprezintă argumente ce vor fi transmise comenzii executate. În C, aceste argumente pot fi accesate prin vectorul argv.

    • Variabila de mediu PATH

  • Atunci cînd primul element din linie este o comandă, shell-ul se comportă diferit dacă aceasta este o cale spre un fișier ce conține semnul / sau dacă este doar un șir de caractere. În primul caz, va lansa în execuție exact fișierul specificat. În al doilea, dacă nu e vorba de o comandă internă, alias sau altceva interpretat direct de către shell, fișierul executabil este căutat într-o listă de directoare. Această listă se află în variabila de mediu PATH și este sub forma unor căi de director despărțite prin semnul : (două puncte). Pentru a vedea conținutul acestei variabile, folositi comanda:

    • echo $PATH

  • Astfel, dacă dorim să executăm un program aflat în directorul curent, iar acest director nu se află în PATH, trebuie să specificăm explicit o cale către el. De aceea, folosim o linie de genul:

    • ./program

    • Punctul reprezintă directorul curent, așa cum .. reprezintă directorul părinte. Slash-ul este despărțitorul de cale. Astfel, interpretorul de comenzi nu va mai căuta în lista de directoare din PATH, deoarece are o cale exactă către fișierul pe care dorim să îl executăm.

    • Mecanisme de citare

  • Deseori avem nevoie ca anumite caractere cu semnificație specială pentru shell să nu fie interpretate special, ci ca și caractere normale. Spre exemplu, să zicem că dorim să ștergem un fișier care are în numele său un spațiu, My Pictures. Comanda:

    • rm My Pictures

    • va afișa o eroare, deoarece nu găsește fișierele My și Pictures. Interpretorul de comenzi sparge linia în trei elemente: numele comenzii - rm - și două argumente: My și Pictures. Pentru a evita această situație, trebuie să facem cumva ca tot șirul My Pictures să fie transmis ca un singur argument comenzii rm.

    • Pentru astfel de situații avem la dispoziție mecanismele de citare:

    • Folosind aceste mecanisme, putem acum șterge fișierul de mai sus în unul din modurile următoare:

    • rm My\ Pictures rm "My Pictures" rm 'My Pictures'

    • Pentru a observa diferența dintre ultimele două mecanisme, rulați următoarele două linii:

    • echo "Path is: $PATH" echo 'Path is: $PATH'

    • Încheierea programelor, oprirea temporară a execuției și marcarea sfârșitului de fișier

  • Terminalul accepta mai multe combinații de taste cu semnificație specială. Dintre ele, amintim următoarele:

    • Un program rulează în foregroun dacă se așteaptă terminarea lui pentru a se citi și interpreta următoarea comandă. Un program executat în background va rula în paralel cu comenzilee care le dăm în continuare, shell-ul citește aceste comenzi și le interpretează și în timp ce comanda rulează.

    • Depanare

  • In general este bine ca atunci cind cream fisierul executabil sa utilizam optiunea -g a compilatorului:

  • gcc -Wall -g -o foo foo.c

  • Asa, in executabilul foo vor fi incluse si simboluri utile pentru depanare.

    • Strategii simple de depanare:

      1. printf()-uri prin cod: tipariti mesaje pe consola pentru a urmari executia programului, eventual cu valori ale variabilelor "interesante". Atentie: este bine sa puneti "\n" la sfirsitul acestor linii, in caz contrar ele nu vor fi imediat tiparite (buffer-ele bibliotecii standard C, atunci cind se lucreaza cu terminale/console, nu sint golite decit explicit cu fflush() sau la intilnirea caracterului newline).

      2. gdb: comanda gdb este un debugger, utilizarea lui nu este foarte simpla; exista si interfete grafice pentru el, de exemplu kgdb sau ddd

      3. valgrind:

      4. strace:

1. Interfeţe cu utilizatorul

Orice sistem de operare deţine o interfaţă prin intermediul căreia realizează comunicarea cu operatorul uman. Primele sisteme de operare aveau interfeţe foarte simple, formate dintr-un set mic de comenzi de bază. Spre exemplu, CP/M, un sistem destinat microcalculatoarelor cu procesoare pe 8 biţi (de exemplu Z80), avea aproximativ 5 comenzi. Odată cu trecerea timpului, interfeţele dintre sistemele de operare şi utilizator au devenit din ce in ce mai complexe, oferind mai multe facilităţi şi uşurând munca de configurare şi întreţinere a calculatoarelor pe care le deservesc.

Pentru a vedea care sunt avantajele şi dezavantajele diferitelor sisteme de operare în ceea ce priveşte interfaţa cu utilizatorul, să încercăm mai întâi să realizăm o clasificare a interfeţelor. În primul rând, trebuie remarcat faptul că interfaţă este orice instrument care permite comunicarea între un sistem de operare şi un operator, indiferent dacă acest instrument este de natură hardware sau software. Din această perspectivă, putem observa următoarele tipuri de interfeţe cu utilizatorul:

    • Interfeţe hardware. De exemplu, tastatura unui mic calculator de buzunar poate fi considerată o interfaţă hardware.

    • Interfeţe software. Acestea sunt reprezentate de sisteme de programe care, sub o formă sau alta, iniţiază şi întreţin un dialog cu utilizatorul calculatorului, în scopul utilizării şi / sau configurării acestuia. Ele formează cvasitotalitatea interfeţelor cu utilizatorul incluse în sistemele de operare, deci ne vom ocupa numai de ele. Interfeţele software pot fi:

      • Monitoare. Unele calculatoare conţin, stocat într-o memorie ROM internă, un program numit monitor, care se lansează automat la pornirea calculatorului şi îi permite utilizatorului să efectueze operaţii simple asupra sistemului de calcul, cum ar fi: inspectarea şi modificarea regiştrilor procesorului, vizualizarea şi alterarea conţinutului memoriei etc. De obicei, programul monitor porneşte în cazul în care nu a putut fi încărcat sistemul de operare.

      • Interfeţe în linie de comandă (sau interfeţe text). Acestea sunt reprezentate, în general, de un program numit interpretor de comenzi, care afişează pe ecran un prompter, primeşte comanda introdusă de operator şi o execută. Comenzile se scriu folosind tastatura şi pot fi însoţite de parametri. Aproape toate sistemele de operare includ o interfaţă în linie de comandă, unele foarte bine puse la punct (cazul sistemelor Unix) iar altele destul de primitive (MS-DOS şi MS-Windows).

    • Interfeţe grafice. Sunt cele mai populare interfeţe cu utilizatorul şi se prezintă sub forma unui set de obiecte grafice (de regulă suprafeţe rectangulare) prin intermediul cărora operatorul poate comunica cu sistemul de operare, lansând aplicaţii, setând diferite opţiuni contextuale etc. Dispozitivul cel mai folosit în acest caz este mouse-ul, de aceea acest tip de interfaţă este utilă în primul rând utilizatorilor neexperimentaţi şi neprofesioniştilor.

Avantaje şi dezavantaje ale diferitelor categorii de interfeţe

Tabelul următor prezintă, comparativ, caracteristicile interfeţelor cu utilizatorul.

Interfaţa în linie de comandă

Avantaje:

  • Permite scrierea clară şi explicită a comenzilor, cu toţi parametrii bine definiţi

  • Oferă flexibilitate în utilizare

  • Comunicarea cu sistemul de operare se face rapid şi eficient

Dezavantaje:

  • Operatorul trebuie să cunoască bine comenzile şi efectele lor

  • Este mai greu de utilizat de către neprofesionişti

Interfaţa grafică

Avantaje:

  • Este intuitivă şi uşor de folosit

  • Poate fi utilizată şi de către neprofesionişti

  • Creează un mediu de lucru ordonat

  • Permite crearea şi utilizarea de aplicaţii de complexe, precum şi integrarea acestora în medii de lucru unitare

Dezavantaje:

  • Anumite operaţii legate, de exemplu, de configurarea sistemului pot să nu fie accesibile din meniurile şi ferestrele interfeţei grafice

  • Interfaţa ascunde anumite detalii legate de preluarea şi execuţia comenzilor

  • Foloseşte mai multe resurse şi este mai puţin flexibilă decât interfaţa în linie de comandă

Interfata in linie de comanda UNIX

Comenzi UNIX

În modul linie de comandă, Unix prezintă mult mai multe facilităţi decât MS-DOS. Interpretorul de comenzi (care porneşte după introducerea numelui utilizatorului şi a parolei) poate fi ales de către utilizator. Există mai multe interpretoare clasice, fiecare răspunzând anumitor cerinţe. Interpretorul "standard" în Unix este sh, dar foarte folosite sunt şi bash, tcsh, ksh, csh.

Comenzile Unix sunt de fapt programe executabile care pot fi găsite în directoarele /bin, /usr/bin. Diferenţele între interpretoarele de comenzi (numite şi shell-uri) se văd mai ales în contextul fişierelor de comenzi. Practic, aceste interpretoare permit scrierea de adevărate programe, complexe, folosind comenzile Unix şi directivele speciale.

Iată, în continuare, principalele comenzi Unix (fişierele de comenzi urmând a fi tratate mai târziu):

man [opţiuni] [secţiune] comandă

Este una dintre cele mai importante comenzi. Ea are ca efect afişarea paginii de manual care descrie comportarea comenzii date ca argument. Manualul este împărţit în secţiuni, numerotate de la 1 la 8. Cele mai importante secţiuni sunt:

    • Secţiunea 1 - Descrie comenzile standard

    • Secţiunea 2 - Funcţiile sistem Unix, apelabile în C

    • Secţiunea 3 - Funcţiile de bibliotecă C

    • Secţiunea 5 - Formate ale diferitelor fişiere specifice sistemului UNIX

    • Secţiunea 8 - Comenzi de administrare a sistemului, cu privilegii sporite

Pentru fiecare secţiune există câte un capitol introductiv care descrie conţinutul acesteia. Pentru a vedea, de exemplu, introducerea la secţiunea 4, se scrie:

man 4 intro

Este, de asemenea, posibilă citirea unei pagini de manual referitoare chiar la comanda man:

    • man man

pwd

tipăreşte numele directorului curent

cd director

schimbă directorul curent

ls [-adgilrst] fişier ...

afişează conţinutul unui director

mkdir director

creează directorul cu numele precizat

rmdir director

şterge directorul precizat, dacă este gol.

cat <lista de fişiere>

afiseaza la fişierul standard de ieşire conţinutul fişierelor date în listă (se pot astfel concatena mai multe fişiere)

lpr [optiuni] fişier

tipăreşte la imprimantă fişierele date

wc [opţiuni] [fişiere]

numără caractere, cuvinte şi linii in fişiere

grep [opţiuni] [şir de caractere] fişier

filtrează liniile unui fişier, căutând şabloane

find director ... condiţie

se caută în directoarele date şi în subdirectoarele lor fişierele care satisfac condiţie. De exemplu, comanda find . -print afişează toate fişierele din subarborele curent.

od [opţiuni] fişier

afişează conţinutul unui fişier în diferite formate: octal, zecimal, hexa, ASCII etc.

rm [opţiuni] fişier ...

şterge fişierele date

mv fişier1 fişier2

mv fişier director

schimbă numele fişier1 în fişier2 sau mută fişier în directorul director

cp fişier1 fişier2

cp fişier ... director

copiază fişier1 în fişier2 sau fişier în director

ln fişier1 [fişier2]

creează o nouă intrare în director pentru fişierul precizat

chmod drepturi fişier

schimbă drepturile de acces ale unui fişier

df [sistem de fişiere]

afişează informaţii despre un sistem de fişiere (disc, partiţie etc): spaţiul total, spaţiul liber şi altele. Sistemul de fişiere poate fi indicat prin directorul în care partiţia sau discul respectiv este montat, adică "rădăcina" sistemului de fişiere. Mai multe detalii despre sistemele de fişiere, structura lor şi modul de montare pot fi găsite în Lucrarea 4 .

du [opţiune] [director]

afisează informaţii privind spaţiul ocupat de fişierele dintr-un director (inclusiv subdirectoarele sale). du . afişează aceste informaţii pentru directorul curent.

ps [opţiuni] [proces]

afişează starea proceselor care rulează pe sistem la momentul curent. Un proces este, în principiu, un program aflat în execuţie, împreună cu stiva sa şi zona de date proprie. Detalii, în Lucrarea 5.

kill proces

oprirea unui proces în curs de execuţie

test expresie

se evaluează expresie, iar dacă valoarea ei este adevărat se returnează 0. Condiţiile se referă la fişiere, directoare, şiruri etc.

date

afişează data şi ora curente

who [am I]

afişează numele utilizatorilor conectaţi la sistem

echo [-n] argumente

afişează argumentele date

login [utilizator]

intrare în sistem

logout

ieşire din sistem

Încercaţi principalele comenzi Unix. Folosiţi comanda man pentru a afla parametrii pe care acestea le pot primi şi semnificaţia lor.