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. | ||