Nguyên nhân
Trước hết, để có thể tìm được vị trí gây nên lỗi, chúng ta hãy dùng đoạn chương trình đơn giản sau:
Program Test;
Uses Crt;
Begin
Writeln('Hello');
End.
Rõ ràng, chương trình này chỉ viết chữ Hello lên màn hình. Khi các bạn chạy chương trình sẽ nhận được thông báo lỗi: Runtime error 200 at ****:0091. **** là địa chỉ segment gây lỗi, có thể khác với mỗi máy tùy theo các chương trình đã nạp trong bộ nhớ. 0091 là offset của đoạn mã lệnh gây nên lỗi.
Nếu bạn bỏ dòng thứ 2: Uses Crt thì chương trình lại chạy một cách "ngon lành". Sở dĩ chúng ta có thể bỏ dòng này là vì hàm writeln duy nhất dùng trong chương trình vừa thuộc unit SYSTEM ngầm định, vừa thuộc unit CRT. Trong trường hợp dùng lệnh Uses CRT, CRT.Writeln sẽ được gọi. Trái lại, SYSTEM.Writeln sẽ được sử dụng nếu bạn không viết Uses CRT. Vậy, lỗi có liên quan tới unit CRT.
Giữ nguyên dòng Uses CRT, và thêm dòng:
SYSTEM.writeln('System Hello')
vào trước dòng writeln('Hello'). Khi chạy chương trình, bạn cũng sẽ chẳng thấy dòng System Hello hiện ra, mà hệ thống vẫn đưa ra câu báo lỗi tương tự. Như vậy, phần mã gây lỗi nằm trước mã lệnh SYSTEM.Writeln(System Hello).
Từ 2 nhận xét trên, có thể phán đoán ngay phần mã gây lỗi là phần khởi động của unit CRT-phần được thực hiện đầu tiên khi chương trình Test được nạp vào bộ nhớ.
Cách giải quyết
Mọi vấn đề "đau đầu" nói trên sẽ được giải quyết bằng cách thay đổi nội dung tập tin CRT.TPU. Thông thường, khi bạn khởi động TURBO PASCAL (TP) hay BORLAND PASCAL (BP), CRT.TPU sẽ được hệ thống tự động nạp khi đọc TURBO.TPL (TPL=Turbo Pascal Library). Nhiệm vụ của chúng ta là thay đổi unit CRT trong TURBO.TPL.
C1: nếu cho mình là một lập trình viên Pro, hãy làm như sau:
Trước khi tiến hành các bước sau, hãy lưu lại tập tin TURBO.TPL trong \BP\BIN để đề phòng mọi bất trắc.
Bước 1: Sửa lại nội dung unit CRT
Với một bản cài đầy đủ của Borland Pascal 7.0, bạn sẽ có thư mục \BP\CRT, trong đó có 2 tập tin CRT.ASM và CRT.PAS. Đầu tiên, hãy thay đổi nội dung CRT.ASM như sau (hãy bấm Ctrl Q-L và tìm từ DelayLoop và phần mã sau):
; Delay one timer tick or by CX iterationsDelayLoop:
@@1:
SUB AX,1
SBB DX,0
JC @@2
CMP BL,ES:[DI]
JE @@1
@@2: RET
trở thành:
; Delay one timer tick or by CX iterations
DelayLoop:
@@1:
push ax ; bắt đầu các hàng chèn thêm
push cx push dx
mov ax,0
mov cx,1
mov dx,0
div cx ;với 10 lệnh div cx, DelayCount = 5F0h div cx; đủ cho bạn chạy với CPU có tốc độ < 8GHz
div cx ; về mặt lý thuyết.
div cx
div cx
div cx
div cx
div cx
div cx
div cx
pop dx
pop cx
pop ax ; kết thúc các hàng chèn thêm
SUB AX,1
SBB DX,0
JC @@2
CMP BL,ES:[DI]
JE @@1
@@2: RET
Như tôi có trình bày ở phần trên, các dòng chèn thêm không thực hiện bất cứ một lệnh gì mà chỉ đơn thuần là làm chậm vòng DelayLoop lại. Điều này không có nghĩa là đồng hồ hệ thống sẽ chậm lại mà chỉ đơn thuần làm chậm vòng DelayLoop và giảm số lần lặp xuống.
Lệnh nguyên thủy SUB và SBB của vòng lặp được giữ nguyên, các lệnh DIV (sau khi lưu nội dung thanh ghi AX, CX, DX bằng loạt lệnh PUSH) nhằm làm chậm hơn vòng lặp. Sở dĩ tôi chọn các lệnh này là vì DIV là lệnh tiêu tốn nhiều clock của CPU (lệnh mất nhiều thời gian thực hiện). Bạn có thể thêm số lần DIV nếu cảm thấy cần thiết. Cuối cùng, loạt lệnh POP hoàn trả lại nội dung các thanh ghi.
Bước 2. Chép tập tin SE.ASM từ thư mục \BP\SYS vào thư mục \BP\CRT. Tập tin SE.ASM chứa một số định nghĩa cho quá trình dịch các Unit của Borland (hay Turbo) Pascal.
Bước 3. Tiến hành dịch CRT.ASM bằng lệnh:
\BP\BIN\TASM CRT.ASM
Máy sẽ phát ra một vài cảnh báo về cách sử dụng tên biến. Cứ "nhắm mắt làm ngơ", chẳng có gì nghiêm trọng đâu.
Bước 4. Chạy Borland Pascal và tiến hành dịch (bấm F9) \BP\CRT\CRT.PAS để tạo ra CRT.TPU. Chép CRT.TPU vào thư mục \BP\BIN.
Bước 5. Chuyển thư mục hiện thời qua \BP\BIN
Xóa unit CRT trong TURBO.TPL bằng lệnh:
TPUMOVER TURBO.TPL -CRT
Sau đó, đưa unit CRT mới sửa vào TURBO.TPL
TPUMOVER TURBO.TPL +CRT
TURBO.TPL đã sẵn sàng. Hãy khởi động lại Borland Pascal. Hy vọng rằng mọi hàm của bạn đều được thực hiện một cách chính xác và Turbo Pascal sẽ chẳng còn phát ra những thông báo lỗi khó chịu "Run time error 200" khi bạn sử dụng unit CRT nữa.
Giải pháp cho các chương trình Pascal đã biên dịch nhưng không còn source
Chắc rằng trong số các chương trình bạn đã biên dịch bằng Borland Pascal 7, một số chương trình sử dụng unit CRT cũng sẽ gặp phải lỗi Division Error kể trên. Nếu các bạn còn giữ source, biên dịch lại chương trình với unit TURBO.TPL đã hiệu chỉnh không phải là "chuyện lớn". Thế nhưng phải làm thế nào nếu bạn không còn hay không có source các chương trình trên.
Để ý rằng do chương trình EXE đã được dịch, việc thay đổi vòng lặp DelayLoop để không ảnh hưởng tới các phần khác của chương trình là không thực hiện được. Do đó, chúng ta cần thay đổi trực tiếp đoạn mã lệnh gây lỗi.
Giải pháp tôi xin đề cử tới các bạn là thay đoạn lệnh:
****:008e: mov CX,55
****:0091: div CX
bằng một lệnh đơn giản: mov AX,0FFFFh vì FFFFh là giá trị tối đa mà DelayCount (biến dạng word 2 byte) có thể nhận được. Tuy nhiên, để không làm biến đổi địa chỉ các phần khác, bạn nhớ đặt thêm 1 lệnh 2 byte trước lệnh move này (do 2 lệnh nguyên thủy chiếm 5 byte bộ nhớ còn lệnh mov AX,0FFFFh chỉ chiếm 3 byte. Giải pháp này dẫn tới việc nếu bạn dùng hàm delay, máy tính sẽ chờ ít hơn (nhanh hơn) so với thời gian bạn yêu cầu, tuy nhiên trong đa số các trường hợp, điều này không dẫn tới hậu quả gì nghiêm trọng. Để tránh sự phiền hà khi tìm kiếm và thay đổi phần mã gây lỗi, tôi có kèm thêm chương trình PATCH.EXE (có thể chép tại Tòa Soạn PCW). Chương trình này sẽ tự động thực hiện việc thay đổi đoạn mã kể trên. Chỉ có đôi điều bạn cần lưu ý:
1. Chỉ dùng PATCH với các chương trình phát sinh lỗi khi chạy như kể trên.
2. Hãy lưu file nguyên thủy trước khi thực hiện thay đổi.
C2: Nếu bạn không muốn mất thời gian thì hãy tải file này về sau đó copy đè lên file cũ là xong










Trả lời + trích dẫn



