Chào mừng đến với Diễn đàn lập trình - Cộng đồng lập trình.
Trang 1 của 2 12 CuốiCuối
Kết quả 1 đến 10 của 16
  1. #1
    Ngày tham gia
    Sep 2015
    Bài viết
    0

    Nghệ thuật Traps Code trong Visual C++

    I. MỞ ĐẦU

    Traps Code là gì vậy? Nói nôn na đó là 1 kỹ thuật Debug bằng cách đặt bẫy trên những đoạn code.

    Dĩ nhiên bất kỳ ai trong chúng ta học lập trình cũng đều biết Debug. Nhưng có bao giờ bạn rơi vào trường hợp phải khóc vì Debug chưa? Ví dụ như là Debug trong MultiThread hay trong Đệ Quy chẳn hạn.

    Thậm chí có lúc bạn phải lập trình mà ko cần Debug. Ví dụ như lập trình PHP chẳn hạn. Các trình dịch GCC thì Debug lại khó khăn hơn VC++ rất nhiều.

    Do đó hầu như trình biên dịch nào cũng hộ trợ một số function giúp bạn làm việc này tốt hơn.

    Mình sẽ mở đầu đề tài này bằng 1 đoạn code tương đối kỳ cục như sau:


    Mã:
    int _tmain(int argc, _TCHAR* argv[]){    {        int i = 100;        printf("%d
    ",i);    }     {        int i = 100;        printf("%d
    ",i);    }     return 0;}
    Đoạn code trên không sinh ra lỗi (vì mình đã dịch rồi) mặc dù int i được khai báo tới 2 lần nhưng nó lại ở 2 block khác nhau { }.

    Trình biên dịch hỗ trợ điều này để giúp ta viết MACRO. Ta sẽ viết đoạn code trên bằng macro DUMP như sau:


    Mã:
    #define DUMP() \    {\        int i = 100;\        printf("%d
    ",i);\    } int _tmain(int argc, _TCHAR* argv[]){    DUMP();    DUMP();    DUMP();    return 0;}
    Kết quả sẽ ra 3 lần sô 100 (giá trị i).

    Tiếp tục 1 lần nữa nhé:

    Mã:
    #define DUMP_INT(VAL) {printf("%s = %d
    ",#VAL,VAL);} int _tmain(int argc, _TCHAR* argv[]){    int a = 100;    int b = 200;    int c = 300;     DUMP_INT(a);    DUMP_INT(b);    DUMP_INT(c);     return 0;}
    Trong đoạn macro trên thì VAL mang giá trị của biến, còn #VAL lại mang tên biến. Do đó nó xuất ra trên màn hình như sau:

    Trích dẫn Gửi bởi Kết quả output:
    a = 100
    b = 200
    c = 300
    Press any key to continue . . .
    Hy vọng nhưng đoạn code kỳ quặc trên sẽ làm bạn thấy 1 chút gì đó thú vị.
    Mình sẽ tiếp tục bài viết này sau...

  2. #2
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    II. BUG FILE & LINE CODE

    Bây giờ code tiếp 1 đoạn đơn giản thôi:


    Mã:
    int main(){    printf("%s - %d
    ", __FILE__, __LINE__);}
    Kết quả sẽ là:
    Trích dẫn Gửi bởi Output
    c:\users\compaq\desktop\debugpointer\debugpointer\ debugpointer.cpp - 97
    Press any key to continue . . .
    Ở trên ta dùng 2 macro đặc biệt được trình biên dịch khai báo hỗ trợ.

    __FILE__: Trả về tên code file (.c hay .cpp) đang thực thi hành
    __LINE__: Trả về dòng đang thi hành.

    Kết quả in ra như vậy vì hàm printf của mình nằm ở dòng thứ 97.

    Chúng ta sẽ lợi dùng 2 macro này để hỗ trợ đánh dấu BUG.

  3. #3
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    III. TRACE

    Trong các trường hợp trên mình đều in kết quả ra màn hình Console nhưng không hẳn trong mọi chương trình của sổ console luôn xuất hiện.

    Chúng ta cũng có thể chọn giải pháp in bug ra file. Và kiểm soát lỗi trên file LOG này.

    Tuy nhiên mình sẽ bug ra 1 của sổ tương đối khá đặc biệt. Đó chính là cửa sổ Ouput của trình biên dịch.

    Ta sẽ làm quen với hàm: OutputDebugStringA. Hàm này của WINAPI (windows.h). Hầu như mọi trình biên dịch đều hỗ trợ nó.


    Mã:
    #include <windows.h>int main(){    char lpStringDebug[100];    sprintf(lpStringDebug,"MY DEBUG: %s - %d
    ", __FILE__, __LINE__);    OutputDebugStringA(lpStringDebug);}
    Kết quả màn hình là dòng mình đã gạch chân bằng màu đỏ.


    Output của trình biên dịch là một cửa sổ khá lý tưởng để DEBUG. Tuy nhiên đoạn code Debug trên làm mình mất hết 3 dòng CODE và rất lằng nhằng nữa. Hình sẽ cải tiến nó thành 1 Macro như sau.


    Mã:
    #define ZDEBUG_TRACE(FORMAT,...) \    { \        char debugString[200]; \        sprintf(debugString,FORMAT, __VA_ARGS__); \        OutputDebugStringA(debugString); \    }
    Lúc này mình sẽ đơn giản hơn:


    Mã:
    int main(){       ZDEBUG_TRACE("MY DEBUG: %s - %d
    ", __FILE__, __LINE__);}

  4. #4
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Uổng công tớ viết phần "mở đầu". Chắc tớ viết khó hiểu quá hả?


    Mã:
    #define PI 3.14 void main(){       printf("%f", PI);}
    PI chính là Macro đó.
    Macro là một sự thay thế. Nó được trình biên dịch dịch trước khi chương trình bạn chạy.

    Bạn có thể hiểu như là 1 cách viết tắt.
    Ví dụ ta thường viết tắt là "TP HCM" nhưng khi đọc thì sẽ là "Thành Phố Hồ Chí Minh".

    Mình lấy lại ví dụ DUMP ban đầu.

    Mã:
    #define DUMP() \    {\        int i = 100;\        printf("%d
    ",i);\    } int _tmain(int argc, _TCHAR* argv[]){    DUMP();    DUMP();    DUMP();    return 0;}
    Khi bạn khai báo Macro DUMP như vậy thì khi trình biên dịch hoạt động nó sẽ thay thế chỗ nào có "DUMP thành đoạn lệnh trên".

    Lúc này đoạn code trên thực sự là như thế này:

    Mã:
    int _tmain(int argc, _TCHAR* argv[]){   // DUMP sẽ thay thế thành    {        int i = 100;        printf("%d
    ",i);    }   // DUMP sẽ thay thế thành    {        int i = 100;        printf("%d
    ",i);    }   // DUMP sẽ thay thế thành    {        int i = 100;        printf("%d
    ",i);    }}

  5. #5
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Bài viết của anh Z hay quá [IMG]images/smilies/biggrin.png[/IMG]
    em thấy lão X code chuyên xài Macro, nhiều cái đọc không tài nào hiểu nổi -_-;;
    Tiếp tục kĩ thuật trap đi anh Z. Thêm nữa, nếu anh có thể thì truyền bá kĩ thuật trap trên Linux luôn nhé. Vì linux không có mấy API của Windows

  6. #6
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Xin cảm ơn bạn!

    III. TRACE (tiếp)

    Bây giờ mình sẽ hoàn chỉnh hơn lệnh TRACE

    Mã:
    #include <stdio.h>#include <string.h>#include <stdlib.h> // Nếu chạy ở chế độ DEBUG (F5)#ifdef _DEBUG    #define ZDEBUG_TRACE(FORMAT,...) \    { \        char debugString[200]; \        sprintf(debugString,FORMAT, __VA_ARGS__); \        OutputDebugStringA(debugString); \    }  // Nếu chạy ở mode Release (Ctrl + F5) -> Macro không giá trị!#else    #define ZDEBUG_TRACE(FORMAT,...)#endif double giaithua(int k){    ZDEBUG_TRACE("Module: giaithua(%d)
    ",k);    if (k == 1)    {        ZDEBUG_TRACE("Result Module: giaithua(1) return 1
    ");        return 1;    }    double r = k*giaithua(k-1);    ZDEBUG_TRACE("Result Module: giaithua(%d) return %f
    ",k,r);    return r;} int _tmain(int argc, _TCHAR* argv[]){        double f = giaithua(10);    printf("%f
    ", f);    return 1;}
    Đây là cách mình đã traps 1 hàm đệ Quy đơn giản nhất.

    Kết quả không có gì đặc biệt từ của sổ Console:

    3628800.000000
    Press any key to continue . . .
    Và màn hình Output thể hiện stack của đệ quy


    Màn hình output này chỉ chạy khi bạn bấm F5 (Còn chạy bằng Ctrl+F5 hay .exe từ file thì sẽ không hiển thị).
    Bởi vì mình chỉ định nghĩa Macro ZDEBUG_TRACE chạy ở mode _DEBUG

    Hy vọng sẽ giúp cho các bạn một chút kiến thức gì đó.

    Còn tiếp... mình sẽ cập nhật sau.

  7. #7
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Tớ hỏi chút: macro là gì? Viết macro là như thế nào?

  8. #8
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    tại sao tớ chạy mấy chương trình của bạn thì báo lỗi ở cái biến: _TCHAR* nó chưa được định nghĩa! ?

  9. #9
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Trích dẫn Gửi bởi hahonga3
    tại sao tớ chạy mấy chương trình của bạn thì báo lỗi ở cái biến: _TCHAR* nó chưa được định nghĩa! ?
    @ha..3: code của anh Z chỉ mang tính chất minh họa. Bạn muốn run các code đó thì phải hiểu bản chất của code và những yếu tố cần thiết để chương trình đó chạy được (thư viện)
    Cho nên nếu cậu chưa vững những điều cơ bản như: hàm nào thuộc thư viện nào, sử dụng các hàm đơn giản thế nào, nhìn vào định nghĩa có thể hiểu cách sử dụng...
    thì thread này cậu chưa nên đọc vội

    Mã:
     #include <tchar.h>

  10. #10
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    cảm ơn nhé. Tớ vốn vội vàng. Nhưng nhờ hỏi câu ngớ ngẩn này mà tớ học được một vài điều rồi đó!

 

 
Trang 1 của 2 12 CuốiCuối

Quyền viết bài

  • Bạn Không thể gửi Chủ đề mới
  • Bạn Không thể Gửi trả lời
  • Bạn Không thể Gửi file đính kèm
  • Bạn Không thể Sửa bài viết của mình
  •