Một vài macro hữu dụng trong C
Thấy mọi người đang thảo luận về Macro trong C. Macro có rất nhiều cách sử dụng “ảo diệu”. Nhưng bài này chỉ nói về một số macro hữu dụng cho cho việc thêm log cho code C/C++. Có bao giờ bạn debug một code C/C++ bằng một loạt các lệnh printf không? Rồi đến khi ...
Thấy mọi người đang thảo luận về Macro trong C. Macro có rất nhiều cách sử dụng “ảo diệu”. Nhưng bài này chỉ nói về một số macro hữu dụng cho cho việc thêm log cho code C/C++.
Có bao giờ bạn debug một code C/C++ bằng một loạt các lệnh printf không?
Rồi đến khi fix xong ta lại đi xóa đóng code rác đó vì nếu không xóa đi, khách hàng có thể hỏi :”Dòng đó để làm gì, tại sao lại in ra trị ở đây?”
Có khi nào log của của trình C/C++ nào khiến bạn quá khó để theo dõi vì chúng chẳng được canh lề gì cả. Hoặc có in ra log đấy nhưng quên không in ra thông tin về dòng nào ?
Hoặc bạn đã in quá nhiều log phải tắt một số log đi.
Dưới đây là một số macro dùng cho việc in log, vì cách gọi giống hệt cách gọi các hàm trong C/C++ nên dù có log thì code vẫn không quá khó nhìn.
Link tham khảo:
- http://stackoverflow.com/questions/1644868/c-define-macro-for-debug-printing
- http://c.learncodethehardway.org/book/ex20.html
Ta sẽ có một file chứa vài macro sẽ nói đến ở đây:
debug_macro.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
#ifndef __debug_macro__ #define __debug_macro__ #include <stdio.h> #include <string.h> #include <stdarg.h> // // Khi không cần in ra log nữa ta đơn giản định nghĩa macro NDEBUG (tức là No Debug) bằng dòng bên dưới. // Khi biên dich, các đoạn mã trống do {} while(0); sẽ bị xóa hết do tối ưu. // Vì thế hầu như không ảnh hưởng đến code chính. //#define NDEBUG (1) #ifdef NDEBUG #define log_debug(fmt, ...) do {} while (0) #define log_err(fmt, ...) do {} while (0) #define log_warn(fmt, ...) do {} while (0) #define log_info(fmt, ...) do {} while (0) #else // NDEBUG // // Dành cho việc in ra log debug // #define log_debug(fmt, ...) do { fprintf(stderr, "[DEBUG] %10s:%10d:%15s(): " fmt, __FILE__, __LINE__, __func__,## __VA_ARGS__); } while (0) // // Dành cho việc in ra log lỗi // #define log_err(fmt, ...) do { fprintf(stderr, "[ERROR] %10s:%10d:%15s(): " fmt, __FILE__, __LINE__, __func__,## __VA_ARGS__); } while (0) // // Dành cho việc in ra log lỗi // #define log_warn(fmt, ...) do { fprintf(stderr, "[WARN] %10s:%10d:%15s(): " fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__); } while (0) // // Dành cho việc in ra các thông tin khác. // #define log_info(fmt, ...) do { fprintf(stderr, "[INFO] %10s:%10d:%15s(): " fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__); } while (0) #endif //NDEBUG #endif // __debug_macro__ |
Các sử dụng mấy macro trên khá đơn giản, vì hàm trên được khai báo sử dụng với tham số thay đổi được.
Nên ta sử dụng giống hệt với các hàm printf mà ta vẫn biết.
Ví dụ
1 2 3 4 5 6 7 |
log_debug("Đây là log debug
"); //.... log_err"Đây là log lỗi
"); //... log_info"Đây là log info
"); |
Môt ví dụ sử dụng
Định viết lại “Hello World” kinh điển nhưng thấy nó cũ quá. Và mình thấy giờ thấy đề bài sau chắc cũng sắp thành kinh điển rồi.
Yêu cầu : Viết chương trình mô tả luồng công việc của một programmer.
Mã giả:
- Vận công nghĩ keyword
- Tìm kiếm keyword trên google
- Xem link 1, xem có code sample không? Nếu có đến step 4, nếu không xem link tiếp theo.
- Chạy thử code sample, nếu chạy đúng, thì kết thúc, nếu chạy sai thì trở về step 3 xem link tiếp.
- Xem hết link mà không có kết quả, thì quay lại step 1 nghĩ từ khóa khác.
Các file source code cho chương trình trên như sau:
resultLinks.txt
1 2 3 4 5 6 7 |
"www.lx.com", "www.facebook.com", "www.stackoverflow.com", "www.segmentfault.com", "www.kipalog.com" |
program.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
#include <stdio.h> #include <stdarg.h> #include"debug_macro.h"// #define MAX_LINK_LENGTH (100) #define MAX_NUM_LINK (20) #define N_DUMMY_LINKS (5) #define N_DUMMY_RESULT_SITE (2) // // Dummy danh sách links kết quả tìm kiếm từ google // const char* DUMMY_RESULT_LINKS[] = { #include"resultLinks.txt" }; // // Dummy những site có sample source // const char* DUMMY_HAS_SOURCE_CODE_SITE[]= { "www.stackoverflow.com", "www.kipalog.com" }; // // Hàm tìm kiếm từ khóa trên google, trả về kết quả là danh sách link // void search_google(char* keyword, char result[MAX_NUM_LINK][MAX_LINK_LENGTH], int *nResults) { int i = 0; log_debug("Search google : (keyword=%s) START
", keyword); for (i = 0; i < N_DUMMY_LINKS; i++) { strcpy(result[i], DUMMY_RESULT_LINKS[i]); } *nResults = N_DUMMY_LINKS; log_debug("Search google : (nResults=%d) END
", *nResults); } // // Hàm chạy source sample từ một link đưa vào từ tham số // int runSource(char* link) { int retVal = 1; //log_debug("Run source in (link=%s) START
",link); if (strstr(link, "www.kipalog.com") != NULL) { log_debug("OK, It works!!!!
"); retVal = 1; } else { log_err("Hmm, Bad source (link=%s)
",link); retVal = 0; } //log_debug("Run source in (link=%s) END
",link); return retVal; } // // Hàm kiểm tra một link có chưa sample source hay không. // int hasSampleSource(char* link) { int i = 0; int retVal = 0; //log_debug("Check source (link=%s) START
",link); for (i = 0; i < N_DUMMY_RESULT_SITE; i++) { if (strstr(link, DUMMY_HAS_SOURCE_CODE_SITE[i]) != NULL) { retVal = 1; break; } } //log_debug("Check source (link=%s) END
",link); return retVal; } // // Hàm start-up // int main(int argc, char* argv[]) { char *keyword; char results[MAX_NUM_LINK][MAX_LINK_LENGTH]; int nResults; int i = 0; // Kiểm tra tham số if (2 != argc) { log_err("Invalid parameter, usage: %s <keyword>
",argv[0]); return 0; } // Lấy keyword keyword = argv[1]; // Tìm google search_google(&keyword[0], results, &nResults); if (nResults > 0)// Nếu có kết quả { // Duyệt từng link kết quả for (i = 0; i < nResults; i++) { log_debug("Try (link=%s)
",results[i]); if (hasSampleSource(results[i]))// Kiểm tra xem có sample source hay không { // Chạy thử source sample runSource(results[i]); } else { log_err("No source in link :%s
", results[i]); } } } else{ log_err("Keyword is so difficult (keyword=%s)
", keyword); } return 0; } |
Build xong và chạy.
Kết quả sau khi thực hiện sẽ như thế này: