Đề tài Sự khác nhau giữa C++ trên Windows và Linux

Các control chuẩn

 

Visual C++ 6.0 cho phép chèn các control chuẩn sau đây vào trong ứng dụng PictureBox, Static Text (Label), Edit box (Textbox), GroupBox, Button, Checkbox, RadioButton, ComboBox, ListBox, Scrollbar, Spin, Progressbar, Slider, TreeControl, Tab Control, Animate, RichEdit, DateTime, Month Calendar, IP Address

Mỗi control có một định danh (ID) riêng. ID chính một số nguyên duy nhất

giúp xác định duy nhất một control. Tuy nhiên, để dễ nhớ trong quá trình lập trình, lập

trình viên xác định một control bằng một tên duy nhất (tốt nhất thể hiện BẰNG CHỮ

IN HOA).

Có thể xem định nghĩa của các ID gắn với một tên của control trong tập tin

resource.h.

 

doc21 trang | Chia sẻ: netpro | Lượt xem: 4611 | Lượt tải: 1download
Bạn đang xem trước 20 trang tài liệu Đề tài Sự khác nhau giữa C++ trên Windows và Linux, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
uồn đóng đắt tiền kia, nhưng hoàn toàn phù hợp cho nhu cầu hàng ngày. Trình biên dịch C trên Linux chỉ là một phần GCC (GNU Compiler Collection). GCC có thể dùng được với: C, C++, Objective C, Fortran,… Biên dịch C là "gcc" Biên dịch C++ là "g++". Bộ công cụ phát triển ứng dụng GNU * GNU Compiler Collection (GCC) + Thư việncác hàm tiện ích: libc, libstdc++, … + Các trình biên dịch gcc, g++, gcj, gas, … + Trình khử lỗigdb +Trình tiện ích khác trong binutils như nm, strip, ar, objdump, ranlib (dùng lệnh info binutils để xem thêm) Tiệních: gmake… Sơ lược về hoạt động của g++ trong linux  Trình soạn thảo code và cách thức biên dịch C++ trong linux Biên dịch chương trình C/C++ *Biên dịch (không link) file chương trình nguồn C++ Vd: g++ -c myprog.cpp + Kết quả là file object tên là myprog.o *Biên dịch (không link) main.c có sử dụng các file *.h trong thư mục include/ (dùng tùy chọn -I để chỉ định đường dẫn) Vd: g++ -c -I ../include reciprocal.c +Biên dịch (không link) có tối ưu mã Vd: g++ -c -O2 main.c + Biên dịch có kèm thông tin phục vụ debug => kích thước file output lớn Vd: g++ -g reciprocal.c *Liên kết (link) nhiều file đối tượng (object files) đã có Vd: g++ -o myapp main.o reciprocal.o *Giả sử ứng dụng của bạn gồm nhiều hơn một file source code, e.g main.c và reciprocal.c. Để tạo thành chương trình thực thi, bạn có thể biên dịch trực tiếp bằng một lệnh g++ như sau: Vd: g++ -o myapp main.c reciprocal.c Cách làm thủ công như trên sẽ bất tiện và không hiệu quả khi ứng dụng gồm quá nhiều file. Trong Windows:  Trong windows thi sau khi viết xong đoạn code cho chương trình thì ta chỉ cần nhấn những tổ hợp phím: +F7: Biên dịch chương trình. +Ctrl F5: Để chạy file thực thi. +Shift F5: Để chạy debug. Trong Trường hợp đoạn code bi lỗi thi sau khi nhấn F7 chương trinh sẽ báo lỗi cho ta.Khi đó thì ta nhấn phím F4 để biết được đoạn code của ta bị lỗi gì và ở đâu. II. Cách khai báo thư viện: Thư viện: cả hai đều có thư viện lệnh chuẩn như: string.h,stdio.h…….. Tuy nhiên trong đó thư viện dùng để khai báo hàm nhập và xuất(hàm iostream.h trong windows và iostream trong linux. Xem hình minh họa bên dưới) của của windows và linux lại khác nhau.Một cách chính xác là cách khai báo trong linux cũng có thể dùng trong windows được. Trong Linux không sử dụng thư viện lệnh nhưng thay vào đó lại là lệnh #include Vd: #include Các câu bắt đầu bằng dấu (#) được dùng cho preprocessor . Chúng không phải là những dòng mã thực hiện nhưng được dùng để báo hiệu cho trình dịch. Ở đây câu lệnh #include báo cho trình dịch biết cần phải "include" thư viện iostream. Đây là một thư viện vào ra cơ bản trong C++ và nó phải được "include" vì nó sẽ được dùng trong chương trình. Đây là cách cổ điển để sử dụng thư viện iostream Void main () hay int main () Dòng này tương ứng với phần bắt đầu khai báo hàm main. Hàm main là điểm mà tất cả các chương trình C++ bắt đầu thực hiện. Nó không phụ thuộc vào vị trí của hàm này (ở đầu, cuối hay ở giữa của mã nguồn) mà nội dung của nó luôn được thực hiện đầu tiên khi chương trình bắt đầu. Thêm vào đó, do nguyên nhân nói trên, mọi chương trình C++ đều phải tồn tại một hàm main. Theo sau main  là một cặp ngoặc đơn bởi vì nó là một hàm. Trong C++, tất cả các hàm mà sau đó là một cặp ngoặc đơn () thì có nghĩa là nó có thể có hoặc không có tham số (không bắt buộc). Nội dung của hàm main tiếp ngay sau phần khai báo chính thức được bao trong các ngoặc nhọn ( { } ) như trong ví dụ của chúng ta . Trong windows: Trong linux: Windows: 1. MFC (Microsoft Foundation Class) Thư viện MFC (Microsoft Foundation Class) là thư viện tập hợp các lớp hướng đối tượng đóng gói các hàm API của Windows và các kiểu dữ liệu đặc biệt. Bên cạnh sử dụng thư viện MFC trong Visual C++ 6.0, chúng ta có thể sử dụng các hàm C chuẩn 2. MSDN (Microsoft Developer Network) Trong MSDN, ngoài các tài liệu giới thiệu chi tiết về việc sử dụng những hàm,lớp…, còn có các quyển sách, bài báo kỹ thuật, hay các mẫu code có thể được tận dụng trong việc lập trình. Linux: 1. Static libraries: -- Tên thường có "lib" và mở rộng ".a" Ví dụ: libmyprog.a 2. Shared libraries: -- Tên có "lib" và phần mở rộng ".so" Ví dụ: libmyprog.so Trước khi được sử dụng thì thư viện phải được cài đặt. Việc cài đặt thư viện gần như rất dễ dàng và đơn giản với người đã từng sử dụng Linux. Các thư viện có thể nên cài vào máy là: ncurses, SVGALib và ngoài ra có thể sử dụng các đồ họa cấp cao như GTK/Qt/FLTK thậm chí trực tiếp với X. +Archives (static library) Là tập hợp các file object tạo thành một file đơn nhất Tương tự file .LIB trên Windows Khi bạn chỉ định liên kết ứng dụng của mình với một static library thì linker sẽ tìm trong thư viện đó để trích xuất những file object mà bạn cần. Sau đó, linker sẽ tiến hành liên kết các file object đó vào chương trình của bạn. Cách thức tạo thư viện tĩnh (archive file) Giả sử bạn có hai file mã nguồn chứa hàm là a.c và b.c a.c b.c int func1(){ double func2(){ return 7; return 3.14159; } } Tạo thư viện tĩnh tên là libab.a 1. Biên dịch tạo các file object $ gcc -c a.c b.c 2. Dùng lệnh ar để tạo thành thư viện tĩnh tên là libab.a $ ar cr libab.a a.o b.o 3. Có thể dùng lệnh nm để xem lại kết quả $ nm libab.a 4. Có thể dùng lệnh file để xem file libab.a là loại file gì $ file libab.a Tạo ứng dụng đơn giản có sử dụng hàm thư viện trong a.c Vidu: Tên file là myapp.c int main() { cout<<”Ket qua dung ham func1:”<<func1; cout<<endl; exit(0); } Biên dịch không có link thư viện tĩnh libab.a $ gcc myapp.c /tmp/cc2dMic1.o: In function `main': /tmp/cc2dMic1.o(.text+0x7): undefined reference to `func1' collect2: ld returned 1 exit status Biên dịch có link đến thư viện tĩnh libab.a $ gcc -o myapp myapp.c -L. -lab hoặc gcc -o myapp myapp.c libab.a $ ./myapp Kết quả dùng hàm func1: 7 Thư viện liên kết động (dynamic, shared library) Tương tự thư viện dạng .DLL của Windows Thư mục chứa thư viện chuẩn +/usr/lib, /lib Tạo thư viện liên kết động libab.so từ a.c và b.c 1. Biên dịch tạo các file object có dùng tùy chọn -fPIC $ g++ -c -fPIC a.c b.c 2. Tạo thư viện liên kết động tên là libab.so $ g++ -shared -fPIC -o libab.so a.o b.o 3. Có thể dùng lệnh file để xem file libab.so là loại file gì $ file libab.so Note:libab.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), not stripped. Tạo ứng dụng với file myapp.c như ví dụ trước Biên dịch link với thư viện tĩnh libab.so $ g++ myapp.c Biên dịch có link đến thư viện tĩnh libab.a G++ -o myapp myapp.c libab.so ./myapp Thông báo lỗi:./myapp: error while loading shared libraries: libab.so: cannot open shared object file: No such file or directory--- Tại sao??? Nguyên nhân: do loader tìm trong thư mục thư viện chuẩn như /usr/lib, /lib không có libab.so Cách giải quyết (cũng là cách dùng để triển khai - deploy, một ứng dụng có sử dụng thư viện liên kết động) 1. Nếu có đủ quyền hạn (e.g. root) thì copy các file thư viện chia sẻ và thư mục chuẩn # cp libab.so /lib ./myapp Kết quả dùng hàm func1: 7 2. Nếu không có đủ quyền hạn copy file vào thư mục chuẩn, user phải thay đổi biến môi trường LD_LIBRARY_PATH để chỉ cho loader tìm trong thư mục chứa thư viện. export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. ./myapp Kết quả dùng hàm func1: 7 Một số chú ý khi lập trình với thư viện liên kết động. Kiểm tra xem ứng dụng cuối cùng của mình tạo ra phụ thuộc vào các thư viện liên kết động nào bằng lệnh ldd. Nếu bị thiếu thư viện thì phải khắc phục theo 2 cách ở trên. $ ldd myapp Thông báo: libab.so => not found libc.so.6 => /lib/i686/libc.so.6 (0x42000000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) Trong thư mục hiện tại có 2 thư viện là libab.a và libab.so. Khi đó, linker sẽ ưu tiên liên kết thư viện .so trước. Muốn chỉ định buộc linker tiến hành liên kết tĩnh với thư viện libab.a thì thêm tùy chọn -static $ mv libab.so libab.so.old $ gcc -static -o myapp myapp.c -L. -lab $ ./myapp Kết quả dùng hàm func1: 7 Cách viết thân hàm: Cách viết trong windows cách viết trong linux III – Cách sử dụng: Windows: Workspace Đây là không gian tương tác giúp lập trình viên nhanh chóng chuyển qua lại giữa các lớp, các tập tin hay các tài nguyên trong project. (Tắt/ Mở workspace : Alt + 0 hoặc View/Workspace) Workspace gồm có 3 tab chính (có thể có các tab phụ add-in): ClassView, ResourceView, FileView. Nội dung các tab này được thể hiện ở dạng cây có thể mở rộng, thu hẹp thông qua các nút +, -. ClassView cho thấy hình ảnh tổng thể project dưới dạng các lớp. Trong classview, lập trình viên có thể biết được cấu tạo của một lớp (có những hàm, biến nào; tầm vực hoạt động của các hàm, các biến – public, protected, private). ResourceView cho thấy được những tài nguyên có trong project (dialog, menu, toolbar, bitmap, icon, …). Thực chất đây là phần hiện thực hoá những gì thể hiện trong tập tin resource.h và .rc FileView cho thấy những tập tin có trong project :source file, header file, resoure file và những tập tin được thêm vào sau. Đó là vùng dùng để thiết kế giao diện (các dialog, menu, toolbar) hay viết code cho project. Output Vùng thể hiện các thông báo lỗi (nếu có), các kết quả thực thi (khi có sử dụng Macro), nội dung của biến (ở chế độ Debug) … Các control chuẩn Hộp Control Trong môi trường lập trình VC++ 6.0 có thể thực hiện việc kéo thả các control chuẩn trong khi thiết kế giao diện. Bật/tắt hộp control khi thiết kế thực hiện như sau: nhấn phím chuột phải trên thanh toolbar, một menu như bên tay phải xuất hiện, chọn (không chọn) chức năng Controls. Ngoài ra, cũng có thể vào Tools\ Customize, check vào toolbars ở vị trí Controls. Các control chuẩn Visual C++ 6.0 cho phép chèn các control chuẩn sau đây vào trong ứng dụng PictureBox, Static Text (Label), Edit box (Textbox), GroupBox, Button, Checkbox, RadioButton, ComboBox, ListBox, Scrollbar, Spin, Progressbar, Slider, TreeControl, Tab Control, Animate, RichEdit, DateTime, Month Calendar, IP Address Mỗi control có một định danh (ID) riêng. ID chính một số nguyên duy nhất giúp xác định duy nhất một control. Tuy nhiên, để dễ nhớ trong quá trình lập trình, lập trình viên xác định một control bằng một tên duy nhất (tốt nhất thể hiện BẰNG CHỮ IN HOA). Có thể xem định nghĩa của các ID gắn với một tên của control trong tập tin resource.h. Sự kiện: Trên Windows, các sự kiện xảy ra liên tục (khi có một tác động của người dùng, hay của chương trình lên hệ thống). Windows sẽ tiếp nhận các sự kiện rồi gửi đến cho các ứng dụng đang chạy. Ví dụ : nhấn phím, nhấn chuột trái, nhấn chuột phải, vẽ lại màn hình, thay đổi chọn lựa, bắt đầu chương trình, thoát khỏi chương trình… Các ứng dụng nhận được “thông báo” từ Windows rồi tuỳ theo “nhu cầu” có “tiếp nhận” hay không. Nếu “tiếp nhận” sự kiện thì phải “giải quyết” như thế nào. Việc giải quyết được đặt trong hàm xử lý sự kiện. Sử dụng ClassWizard để tạo hàm xử lý cho các sự kiện (lên chương trình hay lên một control cụ thể). (Phím tắt : Ctrl – W. Ở chế độ thiết kế dialog có thể nhấn phím chuột phải và chọn mục ClassWizard trên menu.). Trên hộp thoại MFC ClassWizard, có thể chọn lựa lớp (trong Class name), ID của đối tượng (Object IDs) cần thêm sự kiện vào (Messages). Sau khi chọn Add Functions, môi trường lập trình sẽ tự động thêm khai báo hàm, cấu trúc hàm vào những vị trí thích hợp trên tập tin .CPP và .H của lớp. Vùng màn hình Context cho biết giá trị của các biến có trong đoạn chương trình đang chạy (kiểm lỗi). Các biến này được đưa vào một cách tự động. Vùng màn hình Watch cho biết giá trị của các biến do lập trình viên mong muốn. Vùng màn hình Call Stack cho biết thứ tự gọi hàm của chương trình. Vùng màn hình Registers cho biết giá trị các thanh ghi. LINUX: Nếu sử dụng C/C++ chuẩn thì cũng như trên windows, sử dụng ubuntu trước tiên bạn phải cài thêm 2 gói là libstdc++-dev và build essential (vì ubuntu chỉ có các gói cơ bản không hỗ trợ cho lập trình). Để cài đặt mở console gõ lệnh: sudo apt-get install libstdc++-dev sudo apt-get install build-essential. Sau khi cài 2 gói này bạn có thể bắt đầu. Sử dụng editor có sẵn là gedit, soạn thảo chương trình của bạn, lưu với *.c/*.cpp (vd: hello.c) Các bước biên dịch trong linux Công cụ dùng biên dịch các chương trình C/C++ Quá trình biên dịch thành file thực thi gồm 4 giai đoạn theo thứ tự như sau: 1. Preprocessing (tiền xử lý) 2. Compilation (biên dịch) 3. Assembly (hợpdịch) 4. Linking (liên kết) Ba bước 1, 2, 3 chủ yếulàm việc với một file đầuvào Bước4 có thể liên kết nhiều object module liên quan để tạo thành file thực thi nhị phân Lập trình viên có thể can thiệpvào từng bước ở trên. Mở console(terminal) gõ lệnh chỉ đến thư mục chứa file nguồn, gõ lệnh biên dịch: g++ hello.cpp -o hello nếu thấy không báo lỗi gì là đã biên dịch thành công, chạy chương trình bạn gõ ./hello Lưu ý executable file trong linux không có phần mở rộng như trong windows (*.exe). Cách biên soạn 1 mã nguồn G++ : Để biên soạn mã nguồn của bạn, trước tiên bạn phải nằm trong thư mục của bạn có mã nguồn file được in Ví dụ, nếu bạn muốn biên tập tin ~ / projects/proj2/proj2.cc, trước tiên bạn cần phải thay đổi để thư mục ~ / projects / proj2 bằng cách sử dụng lệnh cd. Sau khi bạn đang có trong thư mục chính xác, biên soạn các mã nguồn trong các tệp tin proj2.cc bằng cách gõ lệnh sau tại dấu nhắc xterm: g++ proj2.cc g + + proj2.cc Đây là cách cơ bản nhất để biên soạn mã nguồn của bạn.Sau khi bạn gõ lệnh này, 1 trong 2 điều sẽ xảy ra. Hoặc là mã nguồn của bạn sẽ được thi hành mà không có lỗi và biểu diễn ra màn hình rồi trở lại dấu nhắc lệnh : Hoặc mã của bạn sẽ có một vài lỗi trong đó và các lỗi sẽ được hiển thị: Trong đó không có trường hợp tập tin không thi hành được và bạn sẽ được đưa trở về dấu nhắc lệnh . Bây giờ, hãy giả định rằng mã nguồn của bạn đã không có lỗi trong nó. Bằng cách sử dụng lệnh trên, thi hanh một tập tin sẽ được tạo ra trong thư mục hiện thời gọi là a.out. Để thực sự chạy các chương trình, chỉ cần gõ tại dấu nhắc lệnh. / A.out: g + + CỜ CHỌN g + + cho phép lựa chọn để được gắn cờ khi bạn biên soạn mã nguồn. Phần thảo luận này sẽ hiển thị như thế nào để sử dụng 3 của chúng:-g,-Wall, và-o. -g To use the -g flag, simply type it in after g++ and before your source code file: Để sử dụng -g flag, chỉ cần viết nó trong khoảng sau g++ và mã nguồn của bạn : g++ -g source_file.cc g + +-g source_file.cc Những gì các tùy chọn-g sẽ làm là cho phép các tập lệnh thi hành được "debugged" bằng cách sử dụng gdb debugger. -Wall Để sử dụng các -Wall flag, chỉ cần viết nó giống với g-flag: g++ -Wall source_file.cc g + +-Wall source_file.cc -Wall flag sẽ hiển thị tất cả các thông điệp cảnh báo về các lỗi trong mã nguồn của bạn. Nếu cảnh báo chỉ là những tin nhắn mà bạn nhận được khi bạn biên soạn mã nguồn của bạn, thì tập tin vẫn sẽ được thi hành. Chỉ khi có thông báo ERROR thì tập tin mới không được thực hiện. Tuy nhiên, nhiều giáo sư trong các trường sẽ trừ điểm nếu mã nguồn của bạn viết có cảnh báo khi biên soạn. -o -o flag là một trong những công cụ hữu ích. This flag will allow you to rename the executable file from something other than a.out . Cờ này sẽ cho phép bạn đổi tên các tệp tin thi hành thành những tên khác a.out.Để sử dụng tùy chọn-o, đặt nó sau tập tin mã nguồn, theo sau là tên mà bạn muốn cung cấp cho các lệnh thi hành. Ví dụ, để đổi một tập tin tên mã nguồn proj2.cc thành một tập tin gọi là proj2.exe, gõ lệnh sau: g++ proj2.cc -o proj2.exe g + + proj2.cc-o proj2.exe Làm như thế sẽ tạo ra tập tin thi hanh proj2.exe mà bạn sẽ gõ tại dấu nhắc lệnh để chạy chương trình của bạn. Có thể sử dụng nhiều hơn một cờ cùng một lúc khi bạn biên soạn. Ví dụ, giả sử bạn nhập vào sau lệnh g++: g++ -g -Wall proj2.cc -o proj2 Lệnh này sẽ biên soạn tập tin mã nguồn proj2.cc để có thể sửa lỗi với gdb debugger (-g), hiển thị tất cả các thông điệp cảnh báo khi biên soạn (-Wall), và sẽ tạo ra tập tin thi hành gọi là proj2 (-o proj2). Biên soạn chương trình có nhiều file : Để làm như vậy, chỉ cần lập danh sách tất cả các mã nguồn cái này nối tiếp cái kia : g++ source_file_1 source_file_2 source_file_3... g + + source_file_1 source_file_2 source_file_3 .. Ví dụ, bạn có một chương trình chứa trong 3 file: proj2.cc chứa hàm main() với các chức năng chính và là xương sống của chương trình, functions.h chứa các prototypes cho các chức năng mà chương trình của bạn sử dụng, và functions.cc chứa triển khai các cho các chức năng. Để biên soạn 3 phần trên vào một tập tin thi hành, gõ tại dấu nhắc: g++ functions.cc proj2.cc Các lệnh trên sẽ biên soạn hai tập tin nguồn và tạo ra một lệnh thi hành a.out. NOTE - KHÔNG đưa BẤT KỲ file. H nào vào LỆNH g++! Làm như vậy sẽ cho lỗi! Ngoài ra, giống như bạn làm với chương trình đơn, bạn có thể thêm tuỳ chọn cờ khi bạn biên soạn: g++ -g -Wall functions.cc proj2.cc -o proj2 g + +-g-Wall functions.cc proj2.cc-o proj2 Lệnh này sẽ biên soạn hai tập tin nguồn functions.cc và proj2.cc đó, để tập tin thi hành có thể được sử dụng với các gdb debugger (-g), tất cả các biên cảnh báo sẽ được hiển thị (-Wall), và các tệp tin thi hanh sẽ được gọi là proj2 (-O proj2). Tất nhiên, g++ có thêm nhiều chức năng hơn những gì được mô tả trong hướng dẫn này. Để xem có danh sách đầy đủ của lệnh g++, viết tại dấu nhắc lệnh: man g++ Bộ chương trình GNU cũng kèm theo trình info hướng dẫn sử dụng phần mềm rất chi tiết. Bạn có thể yêu cầu info hướng dẫn sử dụng bằng lệnh sau $ info gcc Sau đây sẽ là các tùy chọn của gcc: -x language Đặc tả tường minh ngôn ngữ được sử dụng trong các file input (thay vì để trìnhbiên dịch tự lựa chọn dựa vào phần mở rộng của các tên file). Đặc tả này có ý nghĩa với tất cả các file được đi theo sau nó cho đến khi gặp một –x kế tiếp nữa. Các ngôn ngữ mà trình biên dịch gcc có hỗ trợ là : -x none Tắt bất kì đặc tả ngôn ngữ nào ở đây và trình biên dịch sẽ dựa vào phần mở rộng của các file input để dịch mà thôi -c Compile hoặc assemble các file source nhưng không thực hiện quá trình link. Kết quả của quá trình biên dịch này sẽ tạo ra các file đối tượng. Mặc định thì các file đối tượng được tạo ra sẽ là các file input nhưng được thay thế phần mở rộng .c , .i ,.s,.... -o file Tạo kết quả biên dịch là một file thực thi mà có tên là file -g Giống như tùy chọn –o nhưng file tạo ra cho phép ta có thể debug quá trình thực thi của nó -llibraryname Cho phép liên kết với các thư viện khi dịch Ở đây có một lưu ý đó là thứ tự các tùy chọn khi biên dịch là không quan trọng. IV Debug một chương trình bằng GDB Tất cả các phần mềm đều chứa đựng lỗi. Thông thường thì 100 dòng lệnh là có khoảng 2-5 dòng lệnh bị lỗi ( 2-5%). Các lỗi thường gặp được phân loại và sử dụng một số phương pháp chung để loại bỏ chúng như sau: · Lỗi đặc tả : Nếu như chương trình ngay từ đầu đã đặc tả sai thì chúng sẽ không hoạt động theo yêu cầu là điều tất yếu. Lập trình viên giỏi nhất thế giới cũng có thể viết ra một chương trình sai với ý tưởng của người dùng. Do đó mà trước khi bắt tay vào lập trình (hay thiết kế) bạn cần phải hiểu rõ mục đích mà chương trình mình phải thực hiện là gì. · Lỗi thiết kế : Chương trình cho dù kích thước nhỏ đi chăng nữa thì cũng cần phải thiết kế .Thường thì ít có chương trình nào bắt đầu bằng việc bạn ngồi ngay vào máy gõ lệnh và thế là nó chạy tốt. Hãy dành thời gian để nghĩ xem chương trình của bạn cần được xây dựng theo cách nào, cấu trúc dữ liệu nào cần dùng đến và chúng sẽ được xử dụng ra sao? Nếu lỗi thiết kế xảy ra thì nó có thể làm cho bạn phải ngồi viết lại toàn bộ chương trình. · Lỗi viết mã : Dĩ nhiên mọi người đều có thể gõ sai lệnh. Tuy nhiên, các trình biên dịch đủ sức bắt lỗi cú pháp và bạn không phải lo lắng về vấn đề này. Có một số trình thông dịch không bắt lỗi khi bạn soạn thảo, lỗi chỉ phát sinh khi chương trình đang chạy. Đây là vấn đề cần quan tâm. Lỗi viết mã khó bắt nhất là các lỗi thuộc về logiccủa chương trình. Ví dụ những vòng lặp vô tận không có điều kiện thoát, những lỗi đánh chỉ số mảng vượt quá phạm vi cho phép. Quá trình gỡ lỗi một chương trình có thể được thực hiện bằng cách theo dõi quá trình hoạt động của chương trình bằng các công cụ tự động. Thường các trình debugger kèm theo trình biên dịch sẽ thực hiện công vịêc này. Chương trình của bạn vẫn được biên dịch ra mã nhị phân và chạy như một chương trình bình thường. Tuy nhiên, trình biên dịch sẽ thêm một số thông tin để trình bắt lỗi debugger có thể dựa vào đó hướng dẫn và thực thi chương trình theo yêu cầu tương tác của bạn. Một chương trình nhị phân muốn thêm vào các thông tin gỡ lỗi, bạn biên dịch với tùy chọn là –g (đối với trình biên dịch là gcc) . Chúng ta sẽ xử dụng trình gỡ lỗi gdb của GNU để thực thi và bắt lỗi các chương trình nhị phân được biên dịch với tùy chọn –g. Để bắt đầu , chúng ta hãy thử với một chương trình gây ra lỗi sau. Đây là một đoạn chương trình chỉ phục vụ chức năng cho hàm sort.Việc sắp xếp dựa trên giải thuật Buble Sort. Mảng sắp xếp bao gồm các phần tử có cấu trúc item. Các phần tử được sắp xếp tăng dần theo khóa key. Chương trình debug1.c /*********************************************/ typedef struct { char * data; int key; } item; item array[]={ {"bill",3}, {"neil",4}, {"john",2}, {"rick",5}, {"alex",1}, }; void sort (item * a, int n) { int i=0,j=0; for (;i<n ; i++) { for (j=0;j<n;j++) { if(a[j].key > a[j+1].key) { item t = a[j]; a[j] = a[j+1]; a[j+1] = t; } } n--; } } main() { int i; sort(array,5); for (i=0; i<5;i++) printf("array[%d]= {%d,%s}\n" ,i,array[i].key, array[i].data); exit(0); } /********************************************/ Chúng ta hãy thử biên dịch chương trình : $ gcc debug1.c –o debug Trình biên dịch thực hiện thành công và không đưa ra thông báo lỗi nào cả. Lỗi này thuộc về lỗi logic chỉ phát sinh lúc chương trình thực thi. Khi chạy chương trình thì ta sẽ được kết quả sau: Chúng ta thấy rằng khi chạy chương trình này thì kết quả kết xuất không theo thứ tự mà chúng ta muốn sắp xếp với lại tại vị trí thứ 2 của mảng đã bị sai. Kết quả này là do quá trình chúng ta truy xuất vào các phần tử không có trên mảng. Tùy theo các phiên bản khác nhau của Linux và Unix thì có thể cho ra một thông báo lỗi khác nhau. Do hệ điều hành luôn cấp phát một vùng nhớ dư cho một ứng dụng nào đó nên ở đây tại vị trí của phần tử thứ 2 thì có kết quả (null). Nếu như bây giờ ta sửa lại đoạn chương trình nguồn thì nó sẽ kết xuất ra một thông báo lỗi khác typedef struct { char data[10000000]; int key; } item; Thông báo lỗi bây giờ là Lí do của việc này là khi kích thước của một phần tử quá lớn thì nó sẽ chiếm nhiều vùng nhớ , khi đó ta truy xuất vượt quá kích thước của mảng sẽ đồng thời vượt luôn vùng nhớ dư mà hệ điều hành cấp cho ứng dụng. Để tìm lỗi cho chương trình, chúng ta bắt đầu quá trình biên dịch cho chương trình này lại với chế độ debug $ gcc debug1.c –g –o debug1 $ gdb debug Bạn tương tác với gdb từ dấu nhắc của chương trình. Sau đây là các lệnh cơ bản trong gdb run (r) Thực thi chương trình đang debug cho đến khi gặp một breakpoint break (b) num Thiết lập breakpoint tại hàng thứ num delete break num Xóa breakpoint thứ num disable break num Tạm thời vô hiệu hóa điểm dừng này. enable break num Sử dụng lại breakpoint đã bị vô hiệu hóa. help breakpoint Xem các lệnh chi tiết về breakpoint info breakpoint Xem thông tin về các breakpoint hiện có trong chương trình backtrace Dò vết stack , chúng ta có thể dùng lệnh này để xem lại các bước mà chương trình đi đến lỗi bằng cách lần theo vết stack nơi lưu chứa các lời gọi hàm và trị trả về của hàm. print j In nội dung của một biến hay của một biểu thức nào đó. Để in giá trị của một mảng thì ta cũng làm tương tự print a[0]@5 . Với @5 chỉ ra số lượng phần tử kế tiếp cần in ra. Display In giá trị của một mảng bất kì khi chương trình thực thi tới breakpoint list linenum In linenum dòng code tiếp theo từ vị trí hiện tại, nếu không chỉ rõ số dòng thì gdb sẽ in ra một số lượng dòng nhất định nào đó. Cont (c) Tiếp tục thực thi chương trình cho đến khi gặp một breakpoint mới Next (n) Thực thi dòng lệnh kế tiếp Commands Thực thi một số lệnh được chỉ định khi gặp một breakpoint Quit Thoát khỏi gdb Tiện ích make Tiện ích make cho phép lập trình viên viết đặc tả về các module kết hợp nên một ứng dụng, các module này cần được tích hợp như thế nào để liên kết thành chương trình. Tiện ích make quản lý việc chạy các lệnh dịch, liên kết,... cần thiết. Nó biết rằng chỉ có các file vừa bị sửa đổi mới cần dịch lại. Một makefile thích hợp sẽ giúp lập trình viên tiết kiệm được rất nhiều thời gian. Một số người rất "ngại" make và makefile, nhưng thực ra tạo một makefile khá dễ. Tạo Makefile Qui trình (giản lược) để xây dựng một Makefile như sau: 1. Xác định chương trình biên dịch 2. Xác định tệp đích (tệp thực thi) và các tệp mã máy liên quan 3. Xác định các mối quan hệ phụ thuộc của các tệp mã máy trung gian Ví dụ: giả sử bạn có các tệp stack.h, stack.cpp,

Các file đính kèm theo tài liệu này:

  • docSự khác nhau giữa c++ trên windows và linux.doc