This shows you the differences between two versions of the page.
so:laboratoare:resurse:die [2015/03/22 12:51] razvan.deaconescu [Altă alternativă] |
so:laboratoare:resurse:die [2018/03/02 23:36] (current) mihai.popescu1212 [Macro-ul DIE] |
||
---|---|---|---|
Line 14: | Line 14: | ||
<code c> | <code c> | ||
+ | #include <errno.h> | ||
#define DIE(assertion, call_description) \ | #define DIE(assertion, call_description) \ | ||
do { \ | do { \ | ||
Line 20: | Line 21: | ||
__FILE__, __LINE__); \ | __FILE__, __LINE__); \ | ||
perror(call_description); \ | perror(call_description); \ | ||
- | exit(EXIT_FAILURE); \ | + | exit(errno); \ |
} \ | } \ | ||
- | } while(0) | + | } while (0) |
</code> | </code> | ||
Line 29: | Line 30: | ||
Dacă verificarea specificată prin ''assertion'' eșuează, se afișează detalii despre eroare și se iese imediat din program, deci **nu se eliberează resursele**. | Dacă verificarea specificată prin ''assertion'' eșuează, se afișează detalii despre eroare și se iese imediat din program, deci **nu se eliberează resursele**. | ||
- | ==== Alternativă ==== | + | ==== Altă abordare ==== |
O abordare mai profesionistă, dar un pic mai complexă, presupune folosirea intrucțiunii **goto**. | O abordare mai profesionistă, dar un pic mai complexă, presupune folosirea intrucțiunii **goto**. | ||
Line 45: | Line 46: | ||
int main(void) | int main(void) | ||
{ | { | ||
- | int fd1, fd2; | + | int fd1, fd2; |
- | fd1 = open("file1", O_CREAT | O_RDWR, 0644); | + | fd1 = open("file1", O_CREAT | O_RDWR, 0644); |
- | if (fd1 < 0) { | + | if (fd1 < 0) { |
- | perror("open file1 failed"); | + | perror("open file1 failed"); |
- | goto exit_1; | + | goto exit_1; |
- | } | + | } |
- | fd2 = open("file2", O_CREAT | O_RDWR, 0644); | + | fd2 = open("file2", O_CREAT | O_RDWR, 0644); |
- | if (fd2 < 0) { | + | if (fd2 < 0) { |
- | perror("open file2 failed"); | + | perror("open file2 failed"); |
- | goto exit_2; | + | goto exit_2; |
- | } | + | } |
/* ... rest of the code ...*/ | /* ... rest of the code ...*/ | ||
- | return 0; | + | return 0; |
exit_2: | exit_2: | ||
- | close(fd1); | + | close(fd1); |
exit_1: | exit_1: | ||
- | return -1; | + | return -1; |
} | } | ||
- | </code> | ||
- | |||
- | ==== Altă opțiune ==== | ||
- | |||
- | Un macro DIE_CB, care primește și o funcție ce poate fi folosită pentru cleanup, rezolvând astfel dezavantajul de a nu elibera resursele. | ||
- | |||
- | <code c> | ||
- | fd1 = open("some file", O_CREAT, 0644); | ||
- | |||
- | DIE(fd1 < 0, "invalid file descriptor"); | ||
- | |||
- | fd2 = open("other file", O_CREAT, 0644); | ||
- | |||
- | /* Va apela close(fd1) */ | ||
- | DIE_CB(fd2 < 0, "invalid file descriptor", close, fd1); | ||
</code> | </code> | ||
- | Primește ca parametri extra: un numele unei funcții și lista de argumente ce trebuie pasată funcției. | + | ==== Concluzie === |
+ | Pentru că aplicațiile din laborator și teme urmăresc în primul rând formarea deprinderii de a verifica **mereu** codul de eroare întors de apelurile de sistem, puteți folosi macro-ul DIE în rezolvarea task-urilor din laborator. | ||
- | <code c> | ||
- | #define DIE_CB(assertion, call_description, callback, ...) \ | ||
- | do { \ | ||
- | if (assertion) { \ | ||
- | callback(__VA_ARGS__); \ | ||
- | fprintf(stderr, "(%s, %d): ", \ | ||
- | __FILE__, __LINE__); \ | ||
- | perror(call_description); \ | ||
- | exit(EXIT_FAILURE); \ | ||
- | } \ | ||
- | } while(0) | ||
- | </code> | ||
- | ==== Altă alternativă ==== | ||
- | |||
- | DIE_BLOCK rezolvă problema de a avea funcții pentru fiecare cleanup și dezavantajul de a nu elibera resursele. | ||
- | |||
- | <code c> | ||
- | fd1 = open("some file", O_CREAT, 0644); | ||
- | |||
- | DIE(fd1 < 0, "invalid file descriptor"); | ||
- | |||
- | fd2 = open("other file", O_CREAT, 0644); | ||
- | |||
- | /* Va apela close(fd1) */ | ||
- | DIE_BLOCK(fd2 < 0, "invalid file descriptor", close(fd1)); | ||
- | |||
- | fd3 = open("another file", O_CREAT, 0644); | ||
- | |||
- | DIE_BLOCK(fd3 < 0, "invalid file descriptor", { | ||
- | close(fd1); | ||
- | close(fd2); | ||
- | }); | ||
- | </code> | ||
- | |||
- | Primește ca parametri extra: un block de cod valid. | ||
- | |||
- | <code c> | ||
- | #define DIE_BLOCK(assertion, call_description, cleanup_block) \ | ||
- | do { \ | ||
- | if (assertion) { \ | ||
- | cleanup_block; \ | ||
- | fprintf(stderr, "(%s, %d): ", \ | ||
- | __FILE__, __LINE__); \ | ||
- | perror(call_description); \ | ||
- | exit(EXIT_FAILURE); \ | ||
- | } \ | ||
- | } while(0) | ||
- | </code> | ||
- | |||
- | ==== Concluzie === | ||
- | Pentru că aplicațiile din laborator urmăresc în primul rând formarea deprinderii de a verifica **mereu** codul de eroare întors de apelurile de sistem, puteți folosi macro-ul DIE în rezolvarea task-urilor din laborator. |