Limbajul C

Limbajul C a fost dezvoltat in anii 1970 in cadrul Bell Laboratories, si este derivat din limbajele B, BCPL si CPL. Flexibilitatea si puterea limbajului C au facut ca acesta sa se raspandeasca foarte repede, de exemplu SO Unix care a fost scris initial in limbaj de ansamblare a fost rescris aproape complet in limbajul C.

Ca şi alte limbaje de nivel înalt, limbajul C utilizează blocuri structurale şi programarea modulară, care fac programul uşor de proiectat, citit şi depanat. Limbajul C are sintaxa independentă de procesor, este compact şi este mai relaxat din punctul de vedere al regulilor decât majoritatea limbajelor de nivel înalt (ceea ce poate fi un dezavantaj pentru începători).

Paşii pentru construirea unei aplicaţii

Compilarea este procesul prin care unui fişier ce conţin instrucţiuni într-un limbaj de programare oarecare este transformat într-un set de instrucţiuni de nivel maşină (uneori numit şi cod obiect) ce pot fi executate de către maşina de calcul.

In figura sunt prezentaţi paşii care sunt realizaţi pentru a ajunge de la cod sursa la fişierul executabil pregătit pentru a fi rulat.

Prerpocesare Prerpocesorul accepta la intrare codul sursa si este responsabil pentru eliminarea comentariilor si interpretarea directivelor de preprocesare (aceste directive încep cu caracterul ‘#’).

Compilarea Compilatorul translateaza codul sursa primit de la preprocesor in limbaj de ansamblare.

Asamblarea Asamblorul creaza cod obiect. In Linux fişierel cod obiect sunt identificate prin extensia o. Fişierele obiect nu pot fi executate pentru că lipsesc anumite componente. Pentru a obţine fişierul executabil trebuie realizat şi pasul de linkeditare.

Limkeditarea În acest pas codul obiect este combinat cu librăriile standard C şi cu eventuale alte librării utilizator folosite în cadrul programului şi este generat fişierul executabil. Fişierele executabile în cadrul sistemului de operare Linux nu au restricţie de nume cu privire la extensia acestora ( în Windows fişierele excutabile au extensia .exe sau .com).

Compilare şi linkeditare aplicaţiilor C

Pas 1. Compilare.

Fişierele sursă C\C++ au extensia c, sau cpp. Numele compilatorului C este gcc. Penru a compila un fişier sursă C se foloseşte opţiunea –c. Opţiunea –c specifică compilatorului să genereze doar fişierul obiect. Dacă această opţiune nu este prezentă atunci compilatorul va încerca să realizeze şi pasul de linkeditare pentru a genera fişierul executabil.

% gcc –c exemplu.c

Rezultatul compilării este un fişier obiect exemplu.o. Compilatorul C++ se numeste g++ şi se foloseşte intr-o manieră similară compilatorului gcc.

Pas 2. Linkeditare.

Pentru a genera fişierul executabil pe baza fişierului obiect se execută comanda gcc cu următoarele opţiuni:

% gcc –o prg exmplu.o

Caz în care este generat fişierul executabil prg. Opţiunea –o specifică numele fişierului executabil ce va fi generat. În cazul în care aceasta opţiunea lipseşte numele fişierului executabil este în mod implicit a.out Executarea executarea acestuia din linia de comandă se face cu instrucţiunea:

% ./prg

Paşii 1 şi 2 pot fi realizaţi intr-o singură etapă prin compilarea programului astfel:

% gcc –o prg exemplu.c

Descompunerea aplicaţiilor în mai multe fişiere.

În mod uzual o aplicaţie complexă este formată din mai multe fişiere sursă. Funcţiile programului sunt localizate în diferite fişiere sursă. Unul dintre fişiere va conţine funcţia main, restul fişierelor putând fi privite ca şi fişiere librării.

Programatorul va descompune sistemul în module componente ce interacţionează între ele. Fiecare dintre module va fi implementat în mod uzual printr-un set de funcţii localizate într-un fişier separat.

Avantajele acestui mod de grupare sunt:

  • fişierele de funcţii pot fi uşor reutilizate în alte programe;
  • toate funcţiile care îndeplinesc un anumit scop sunt definite împreună într-un fişier;
  • modificările ulterioare asupra unei funcţii nu necesită recompilare întregului program.

Pentru ca o funcţie dintr-un fişier sursă să poată folosi o funcţie dintr-un alt fişier sursă trebuie ca fişierul ce utilizează un alt fişier să cunoască lista de funcţii la care are acces. Pentru a rezolva această problemă se recomandă scrierea de fişiere de tip header cu nume identic cu fişerul sursă dar cu extensia .h. Fişierele header conţin semnăturile funcţiilor fără implementare.

Exemlu:

Fişierul math.c:

int add(int i, int j){
 return i+j;
}

Fişierul math.h:

int add(int i,int j);

Fişierul exemplu.c:

#include ”math.h”
int main(){
int a,b,c;
a=5;b=9;
printf(%d”,add(a,b));
}

Pentru ca în fişierul exemplu.c şă poată fi utilizată funcţia add(…), la începutul acestuia a trebuit adăugată directiva #include ”math.h”.

Pentru a genera fişierul executabil pentru o aplicaţie compusă din mai mult fişiere sursă se generează fişierele obiect pentru fiecare dintre fişierele sursă după care se linkeditează.

% gcc –c math.c

rezultă fişierul obiect math.o

% gcc –c exemplu.c

rezultă fişierul obiect exemplu.o

% gcc –o app exemplu.o math.o

rezultă fişierul executabil app

Când unul dintre fişierele sursă s-a modificat acesta trebui recompilat şi apoi regenerat fişierul executabil prin linkeditare. Dacă avem de a face cu o aplicaţie complexă cu multe fişiere sursă este util folosirea unui gestionar de fişiere în genul utilitarului make.

Utilitarul Make

Make este o aplicaţie ce ajută programatorul în menţinerea integrităţii unei colecţii de module. Nu este obligatoriu ca aceste module să fie programe ele putând fii orice tip de fişiere. Acest utilitar poate fi folosit atât pentru aplicaţii C cât şi pentru aplicaţii scrise în alte limbaje de programare.

Utilitarul make citeşte instrucţiuni din cadrul unui fişier text pe care apoi le execută. Implicit make citeste instructiunile din fisierul text cu numele Makefile, însă se poate specifica numele oricărui fişier text.

Un fişier Makefile conţine un set de reguli. Conceptul de regula in cadrul fisierelor Makefile specifică cum si când se executa o secvenţă de instrucţiuni. De exemplu să presupunem că avem un proiect care implica compilarea fisierelor sursa exemplu.cc si math.c si producerea fisierului executabil app.

Un exemplu de fisier Makefile care ne ajuta in cadrul proiectului nostru atunci ar fi:

app: exemplu.o math.o
gcc exemplu.o math.o -o app
exemplu.o : math.c
gcc -c exemplu.c
math.o : math.c
gcc -c math.c

Liniile care au in componentă “:” se numesc linii de dependenţă. Ceea ce se află la stânga de “:” reprezintă numele dependentei (sau a regulii), ceea ce se află la dreapta reprezintă regulile de care depinde regula curenta. De exemplu linia project : exemplu..o math.o specifica faptul ca regula de obţinere a fişierului executabil depinde de regulile de formare a fişierelor exemplu.o si math.o. La rulare make compara momentul de timp când fişierul app a fost ultima oara modificat cu momentul de timp la care fişierele exemplu.o si/sau math.o au fost modificate pentru a determina dacă este necesara o recompilare sau nu a vreunuia dintre fişierele sursa.

Pentru a interpreta instrucţiunile din cadrul unui fişier Makefile se lansează instrucţiunea make din directorul curent în care se află acesta.

Paginile Man

Distribuţiile Linux conţin documentaţie pentru comnezile standard, funcţiile sistem şi funcţiile din librăriile standard. Documentatia este organizata pe capitole in felul următor: (1) User commands (2) System calls (3) Standard library (4) System and administrativ commands

Numerele reprezintă secţiunea în care regăsiţi informaţiile respective. Pentru a acesa documentaţia se foloseşte comanda man [section] command. In unele cazuri aceiaşi funcţie se regăseşte descrisă în mai multe secţiuni – în aceste situaţii trebuie specificată secţiunea ca primă opţiune a comenzii man.

% man sleep
% man 3 sleep

Cautarea după un anumit cuvân cheie se poate face folosind instrucţiunea man –k keyword.