Sunteți pe pagina 1din 8

Parametrii liniei de comandă in C si C++

Un program executabil (o comandă) poate fi lansat în execuţie de către interpretorul de comenzi al


sistemului de operare.
De exemplu, programul salut.exe care afişează la terminal mesajul “Buna ziua!” este o
comandă fără parametrii, lansată în execuţie prin:
> salut
O comandă poate avea şi parametri, care apar după numele comenzii şi sunt separaţi prin spaţii
libere.
De exemplu programul salut.exe ar putea avea un parametru şir de caractere, care să specifice un
anumit mesaj, fiind lansat în execuţie, în acest caz prin:
> salut mesaj
Un alt exemplu il constituie un program care copiază un fişier; acesta ar avea doi parametri,
desemnând fişierele sursă şi destinaţie (şiruri de caractere ):
> copiere sursa.dat dest.dat
Parametrii pot fi specificaţi nu numai la nivelul liniei de comandă, ci şi din mediul integrat de
dezvoltare C, folosind opţiunea Parameters din meniul Run.
Programul poate avea acces la parametrii liniei de comandă, dacă funcţia main() prezintă
argumente:
void main(int argc, char *argv[]){ …
}
Primul argument, argc (argumentul contor) este un întreg care reprezintă numărul de parametri ai
comenzii.
Al doilea argument, argv (argumentul vector) este un pointer la un tablou de pointeri la şiruri de
caractere, care conţin argumentele (câte un argument pe şir de caractere).
Prin convenţie, argv[0] conţine întotdeauna numele programului, astfel încât pentru o comandă
fără parametri argc=1, iar o comandă cu 2 parametri va avea argc=3.
argv[1] conţine primul parametru,argv[2] – pe cel de-al doilea, argv[c-1] va conţine
ultimul parametru, iar argv[argc] va fi un pointer la un şir vid (NULL).
Astfel pentru comanda copiere exemplificată mai sus avem:
argv
copiere copiere\0
s sursa.dat\0
dest.dat\0
\0 d

Exemplul Să se copieze la ieşire fişierele date ca parametri ai comenzii. Dacă nu avem


parametri se copiază fişierul standard de intrare (stdin).

#include <stdio.h>
void copy(FILE *, FILE *);
main(int argc, char *argv[])
{ FILE *pf;
if(argc==1)
copy(stdin, stdout);
else
while(--argc)
if((pf==fopen(*++argv,”r”))==NULL) {
fprintf(stderr, “Nu putem deschide %s\n”, *argv);
return 1;

1
}
else {
copy(pf, stdout);
fclose(pf);
}
return 0;
}
void copy(FILE *s, FILE *d)
{ int c;
while((c=getc(s))!=EOF)
putc(c, d);
}

1. Macroinstrucţiuni pentru funcţii cu număr variabil de parametri.


Funcţiile C pot fi apelate cu număr variabil de parametri actuali. (un exemplu îl constituie
funcţiile printf() şi scanf() ).
Programatorul îşi poate scrie propriile funcţii cu număr variabil de parametri, folosind
macroinstrucţiunile din fişierul antet <stdarg.h>.
O funcţie cu număr variabil de parametri va avea prototipul:
tip nume (listă_fixă_parametri, …);
Lista fixă de parametri trebuie să fie nevidă, deci numărul de parametri va fi mai mare sau egal
cu numărul de parametri ficşi.
Parametrii care sunt în număr variabil sunt convertiţi implicit ca tip, şi anume:
• toţi întregii la int
• toţi realii la double
Fişierul antet <stdarg.h> conţine definiţii pentru tipul va_list. Argumentele variabile vor fi
accesate printr-o variabilă pointer pa, declarată astfel:
va_list pa;
Iniţializarea pointerului de acces la argumentele variabile -pa se face folosind
macroinstrucţiunea va_start() , indicând adresa ultimului parametru fix lastarg:
va_start(pa, lastarg);
Pentru parcurgerea listei de argumente variabile se va folosi macroinstrucţiunea va_arg(),
care actualizează pointerul de acces la argumente pa, pentru a indica următorul argument int sau
double, şi întoarce ca rezultat argumentul curent din lista de parametri variabili:
vint=va_arg(pa, int);
sau
vreal=va_arg(pa, double);
Oprirea procesului repetitiv se face folosind informaţiile despre parametrii ficşi (în vârful stivei
se va afla pointerul la format). După ultimul parametru variabil extras se apelează macroinstrucţiunea:
va_end(pa);

Exemplul: Scrieţi o funcţie care afişează un număr variabil de şiruri de caractere (cel mult
max).
#include <stdio.h>
#include <stdarg.h>
int printvar(int max, …);
void main(void)

2
{ printvar(3,”Ion”,”Vasile”,”Mihai”);
printf(“\n”);
printvar(5,”marti”,”joi”,”luni”,”vineri”,”duminica”);
printf(“\n”);
}
void printvar(int max,…)
{ va_list pa;
int narg=0;
char *siruri[10];
va_start(pa,max);
while(narg < max) {
siruri[narg]=va_arg(pa, char*);
printf(“%s \n”, siruri[narg++]);
}
va_end(pa);
}
Extragerea argumentelor variabile, poate fi făcută, şi cu alte funcţii, în loc de va_arg(). În
acest scop se folosesc funcţiile: vprintf(), vfprintf() şi vsprintf(). Acestea au
prototipurile:
int vprintf(char * format, va_list pa);

• afişează, sub controlul formatului, la ieşirea standard, un număr variabil de argumente, accesate
prin pointerul pa
• întoarce numărul de octeţi afişaţi (rezultat negativ la eroare)
Exemplu:
#include <stdio.h>
#include <stdarg.h>
int printvar(char* fmt, …);
void main(void)
{ fmt1[]=”%s %s %s\n”;
printvar(fmt1,”Ion”,”Vasile”,”Mihai”);
}
void printvar(char* fmt,…)
{ va_list pa;
va_start(pa,fmt);
vprintf(fmt,pa);
va_end(pa);
}

int vfprintf(FILE * fis, char * format, va_list pa);

• afişează, sub controlul formatului, în fişierul fis, un număr variabil de argumente, accesate prin
pointerul pa
• întoarce numărul de octeţi afişaţi (rezultat negativ la eroare)
Exemplu:
#include <stdio.h>
#include <stdarg.h>
#define NUMEFIS “fis.dat”
void printvar(FILE* f, char* fmt, …);
void main(void)
{ FILE* f1;
fmt1[]=”%s %s %s\n”;
f1=fopen(NUMEFIS, “w”);

3
printvar(f1,fmt1,”Ion”,”Vasile”,”Mihai”);
fclose(f1);
}
void printvar(FILE* f, char* fmt,…)
{ va_list pa;
va_start(pa,fmt);
vfprintf(f, fmt, pa);
va_end(pa);
}

int vsprintf(char * sir, char * format, va_list pa);

• afişează, sub controlul formatului, în şirul de caractere sir, un număr variabil de argumente,
accesate prin pointerul pa
Exemplu:
#include <stdio.h>
#include <stdarg.h>
int printvar(char* s, char* fmt, …);
void main(void)
{ fmt1[]=”%s %s %s\n”;
char s[100];
printvar(s, fmt1, ”Ion”,”Vasile”,”Mihai”);
printf(“%s”,s);
}
void printvar(char* s, char* fmt,…)
{ va_list pa;
va_start(pa,fmt);
vsprintf(s,fmt,pa);
va_end(pa);
}

Exemplul : Scrieţi o funcţie cu număr variabil de parametri, care simulează funcţia printf(),
acceptând parametri variabili de tip int, double sau şir de caractere.

#include <stdio.h>
#include <stdarg.h>
void printvar(char* fmt,…)
{ va_list pa;
char *p, *psir;
int i;
double d;
va_start(pa,fmt);
for (p=fmt; *p; p++) {
if(*p!=”%”){
putchar(*p);
continue;
}
switch(*++p) {
case ‘d’:
i=va_arg(pa, int);
printf(“%d”,i);
break;
case ‘f’:
d=va_arg(pa, double);
printf(“%lf”,d);

4
break;
case ‘s’:
for (psir=va_arg(pa,char*);*psir;psir++)
putchar(*psir);
break;
default:
putchar(*p);
break;
}
}
va_end(pa);
}

2. Probleme propuse.

1. Scrieţi un program care evaluează o expresie dată prin linia de comandă sub formă poloneză
inversă. Fişierul executabil are numele expresie, iar termenii şi operatorii apar ca parametri. De
exemplu:
expresie 3 5 12 + *
desemnează expresia (3 + 5) * 12 care va fi evaluată ca 96.

2. Scrieţi un program care afişează ultimele n linii ale fişierului de intrare. Programul poate
avea un parametru n, specificat sub forma: ultime –n
In caz că programul este lansat fără parametri, se consideră în mod implicit că n=10.

3. Scrieţi un program care calculează şi afişează cmmdc a mai multor numere naturale.
Numerele sunt date:
• în fişierul standard de intrare, caz în care programul este lansat în execuţie fără parametri:
 cmmdc
• în linia de comandă, ca argumente:
 cmmdc 36 48 18 72 54
• într-un fişier de intrare, a cărui nume apare ca argument al liniei de comandă sub forma:
 cmmdc –nume.dat

Preprocesorul.
Preprocesarea este o fază premergătoare compilării. Comenzile preprocesorului se numesc
directive .
Principalele funcţii ale preprocesorului se referă la:
• Definirea de constante simbolice
• Definirea de macroinstrucţiuni
• Includerea de fişiere
• Compilarea condiţională
Directivele preprocesorului:
• încep în coloana 1 prin ‘#’
• se continuă pe linia următoare cu ‘\’
• pot fi incluse unele în altele

5
1. Definirea de constante simbolice:
#define PI 3.14159265
#define MAX 100
2. Substituirea textuală (definirea de macroinstrucţiuni)
Sunt posibile două alternative:
1. substituţie textuală simplă
#define NUME text
2. substituţie cu argumente
#define NUME(arg1, arg2,…,argn) text
Expandarea in-line a macrourilor este mai rapidă decât apelul de funcţie, dar prezintă dezavantajul
creşterii dimensiunii programului în cazul unor substituiri repetate.
Substituirea textuală nu se efectuează:
• în interiorul şirurilor de caractere
char mesaj[]=”MAX este 100”; /* aici nu se face! */

• în interiorul identificatorilor
int MAXIM=25; /* nici aici nu se face! */
Dacă numele apare şi în textul extins, atunci dezvoltarea se face o singură dată şi nu în mod
recursiv. Astfel:
#define MAX MAX 100
nu se expandează decât o singură dată.
Un nume existent poate fi folosit pentru definirea altui macro. Astfel pentru substituţiile:
#define UNU 1
#define DOI (UNU+UNU)
nu putem inversa ordinea directivelor.
În cazul definiţiilor de macrouri cu argumente, în partea de text se pun argumentele între
paranteze.
Este greşită definirea:
#define PATRAT(x) x*x
deoarece PATRAT(y+1) ar genera y+1*y+1, în timp ce:
#define PATRAT(x) (x)*(x)
generează pentru PATRAT(y+1) textul (y+1)*(y+1).
Dacă în textul de înlocuire un argument este precedat de #, la expandare va apare între ghilimele.
Astfel pentru macrodefiniţia:
#define afisare(expr) printf(#expr “=%g\n”, expr(
afisare(x/y) generează printf(“x/y””=%g\n”, x/y)
Vom da acum câteva macrodefiniţii utile în lucrul cu biţi:
• setarea bitului n din x la 1
#define SET(x,n) ((x)|=(1<<(n)))

• punerea bitului n din x pe 0


#define RESET(x,n) ((x)&=~(1<<(n)))

6
• testul bitului n din x
#define TEST(x,n) ((x)&(1<<(n)))
Numărul de elemente al unui tablou se poate calcula cu macroinstrucţiunea:
#define NELEM(A) )sizeof(A) / sizeof(A[0])
Pentru o substituţie textuală care ocupă mai multe linii, la sfârşitul fiecărei linii care se continuă se
pune \ . Astfel:
#define SWAP(A,B) {\
long t; \
(t)=(A);\
(A)=(B);\
(B)=(t);\
}
Ca restricţii menţionăm:
• macrourile nu se pot apela din alt limbaj de programare
• nu există pointeri la macrouri
• nu toate funcţiile pot fi convertite în macrouri.

3. Includerea de fişiere.
Directiva de includere copiază fişierul text menţionat în textul programului, în punctul în care
apare.
Fişierul inclus se poate afla în acelaşi director cu textul programului, situaţie în care directiva de
includere are forma:
#include “nume”
Dacă fişierul inclus se află într-un director special, pentru a dirija căutarea către acest director se
foloseşte directiva:
#include <nume>
Un fişier inclus poate include la rândul lui alte fişiere.
Includerea de fişiere sursă se foloseşte ca mecanism de legare a programelor mari.
În programele C se include de obicei fişiere antet (cu extensia .h); acestea se află într-un director
cu numele INCLUDE al mediului de programare C şi conţin declaraţii de prototipuri ale unor funcţii de
bibliotecă, definiri de tipuri, etc. Astfel fişierul antet <stdio.h> conţine prototipurile tuturor funcţiilor
folosite în operaţiile de intrare / ieşire.

4. Compilarea condiţionată.
Compilarea condiţională ne permite ca dintr-un text dat să selectăm numai anumite părţi care să
fie compilate.
O serie de directive ne permit să efectuăm verificări condiţionale asupra unor expresii constante
sau asupra valori definite.
Un identificator devine definit dacă apare într-o directivă #define nume, sau poate fi făcut
nedefinit prin #undef nume.
Putem testa dacă un simbol este sau nu definit şi în funcţie de aceasta putem insera text (secvenţe de
instrucţiuni), care să fie compilat, conform uneia din variantele:
Dacă expresie are valoare diferită de 0 se compilează textul cuprins între #if şi #endif

#if expresie
text
#endif

7
Dacă simbolul NUME este definit (nedefinit), atunci se compilează textul cuprins între #if şi
#endif.

#if defined NUME #ifdef NUME #ifndef NUME


. text. text . text
#endif #endif #endif

O formă completă cuprinde ambele alternative ( diferit de zero / zero simbol definit / nedefinit) în
funcţie de care se compilează text_1 sau text_2
#if expresie #ifdef NUME
text_1 . text_1
#else #else
text_2 text_2
#endif #endif

Sunt posibile şi selecţii multiple cu #ifdef, #elif, #else, #endif.


Compilarea condiţională se foloseşte pentru evitarea includerii multiple a unui fişier.

#ifndef STDIO_H
#include <stdio.h>
#define _STDIO_H
#endif

5. Probleme propuse.

1. Definiţi o macroinstrucţiune care interschimbă două valori de orice tip.

2. Definiţi macroinstrucţiuni pentru transformarea literelor mici în litere mari şi invers.