Mục lục bài họcĐang ở d03-b2
Programming languages and translators
High-level and low-level languages
| high-level | close to human language; one statement does a lot; portable between different processors |
| low-level | close to the machine; assembly language uses mnemonics like $\text{LDA}$ and $\text{ADD}$; machine code is pure binary |
High-level languages are easier and faster to write, easier to read and debug, and the same program runs on different machines after re-translation.
Low-level languages give direct control of the hardware and can produce faster, smaller code — but they are hard to write, easy to get wrong, and specific to one processor, so the program will not run on a different type of machine.
Note that high-level is not simply better. It is the right choice for almost all programs, but device drivers and embedded systems still use low-level code where every byte and every cycle matters.
Assembly language and the assembler
Assembly language replaces binary instructions with short mnemonics, so $\text{ADD}$ is far easier to read than a string of bits. Each mnemonic corresponds to one machine-code instruction.
An assembler translates assembly language into machine code.
Compiler and interpreter
Both translate high-level code into machine code, but they work completely differently.
| compiler | interpreter | |
| how it translates | the whole program at once | one line at a time, executing each as it goes |
| output | produces an executable file | produces no file — it must run every time |
| errors | reports all errors together at the end | stops at the first error it meets |
| speed of running | faster — already translated | slower — translating while running |
| source code | user does not need it | user needs it and the interpreter |
The consequence the exam asks about: an interpreter is better for developing and debugging, because it stops exactly at the offending line so the programmer sees immediately where the problem is. A compiler is better for the finished program, because it runs faster and the source code stays private.
Note what "stops at the first error" really means: the interpreter finds errors one at a time, so a program with ten errors must be run ten times. The compiler lists all ten at once — but gives nothing runnable until they are all fixed.
Integrated Development Environments
An IDE brings the tools a programmer needs into one program:
- code editor with line numbering, colour-coded syntax highlighting and auto-completion;
- error diagnostics — underlining mistakes as you type and explaining them;
- a translator — compiler or interpreter, built in;
- a run-time environment to execute the program without leaving the IDE;
- debugging tools — breakpoints to pause execution, and variable watches to see values change.
The benefit is that writing, translating, running and fixing all happen in one place, which makes development far faster than using separate tools.
Ngôn ngữ bậc cao và bậc thấp.
- Bậc cao — gần với ngôn ngữ con người; một câu lệnh làm được nhiều việc; khả chuyển giữa các bộ xử lý khác nhau;
- Bậc thấp — gần với máy; hợp ngữ dùng các từ gợi nhớ như $\text{LDA}$ và $\text{ADD}$; mã máy là nhị phân thuần tuý.
Ngôn ngữ bậc cao dễ và nhanh viết hơn, dễ đọc và dễ gỡ lỗi hơn, và cùng một chương trình chạy được trên nhiều máy khác nhau sau khi dịch lại.
Ngôn ngữ bậc thấp cho quyền điều khiển phần cứng trực tiếp và sinh ra mã nhanh hơn, gọn hơn — nhưng khó viết, dễ sai, và chỉ dùng được cho một loại bộ xử lý, nên chương trình không chạy được trên máy khác loại.
Chú ý bậc cao không đơn giản là tốt hơn. Nó là lựa chọn đúng cho gần như mọi chương trình, nhưng trình điều khiển thiết bị và hệ thống nhúng vẫn dùng mã bậc thấp ở những nơi từng byte và từng chu kỳ đều quan trọng.
Hợp ngữ và trình hợp dịch. Hợp ngữ thay các lệnh nhị phân bằng những từ gợi nhớ ngắn, nên $\text{ADD}$ dễ đọc hơn hẳn một chuỗi bit. Mỗi từ gợi nhớ ứng với một lệnh mã máy.
Trình hợp dịch dịch hợp ngữ thành mã máy.
Trình biên dịch và trình thông dịch. Cả hai đều dịch mã bậc cao thành mã máy, nhưng cách làm hoàn toàn khác nhau.
- Trình biên dịch dịch toàn bộ chương trình một lần, tạo ra một tệp chạy được. Nó báo mọi lỗi cùng lúc ở cuối. Chương trình chạy nhanh hơn vì đã dịch xong, và người dùng không cần mã nguồn;
- Trình thông dịch dịch từng dòng một và chạy ngay dòng đó. Nó không tạo tệp nào, nên phải dịch lại mỗi lần chạy. Nó dừng ngay ở dòng lỗi đầu tiên. Chương trình chạy chậm hơn, và người dùng cần cả mã nguồn lẫn trình thông dịch.
Hệ quả mà đề thi hỏi: trình thông dịch tốt hơn khi đang phát triển và gỡ lỗi, vì nó dừng đúng tại dòng có vấn đề nên lập trình viên thấy ngay lỗi ở đâu. Trình biên dịch tốt hơn cho sản phẩm hoàn chỉnh, vì chương trình chạy nhanh hơn và mã nguồn được giữ kín.
Chú ý ý nghĩa thật của câu “dừng ở lỗi đầu tiên”: trình thông dịch tìm lỗi từng cái một, nên một chương trình có mười lỗi phải chạy mười lần. Trình biên dịch liệt kê cả mười cùng lúc — nhưng không cho gì chạy được cho tới khi sửa hết.
Môi trường phát triển tích hợp. Nó gom các công cụ lập trình viên cần vào một chương trình:
- trình soạn mã có đánh số dòng, tô màu cú pháp và gợi ý hoàn thành lệnh;
- chẩn đoán lỗi — gạch chân lỗi ngay khi gõ và giải thích lỗi;
- trình dịch — biên dịch hoặc thông dịch, tích hợp sẵn;
- môi trường chạy thử để chạy chương trình mà không phải rời khỏi phần mềm;
- công cụ gỡ lỗi — điểm dừng để tạm ngưng chương trình, và cửa sổ theo dõi biến để thấy giá trị thay đổi.
Lợi ích là việc viết, dịch, chạy và sửa đều diễn ra ở cùng một chỗ, nên phát triển nhanh hơn hẳn so với dùng các công cụ rời rạc.
Một lập trình viên đang viết dở một chương trình lớn và sẽ phát hành nó cho khách hàng khi xong. Nêu nên dùng trình thông dịch hay trình biên dịch ở mỗi giai đoạn, và giải thích.
Giai đoạn đang viết và gỡ lỗi → dùng TRÌNH THÔNG DỊCH.
Lý do một — thấy ngay lỗi ở đâu. Trình thông dịch dịch và chạy từng dòng một, và nó dừng đúng tại dòng có lỗi. Lập trình viên biết ngay vấn đề nằm ở đâu mà không phải dò tìm.
Lý do hai — thử nhanh từng đoạn. Không phải dịch lại cả chương trình sau mỗi lần sửa một chữ. Sửa xong là chạy được ngay, nên vòng lặp sửa – thử – sửa rất nhanh.
Lý do ba — chạy được chương trình còn dở. Trình thông dịch chạy tới đâu hay tới đó, nên lập trình viên thử được phần đã viết xong dù phần sau chưa hoàn thiện.
Nhược điểm chấp nhận được ở giai đoạn này: chương trình chạy chậm hơn, nhưng lúc đang phát triển thì tốc độ chạy không quan trọng bằng tốc độ tìm ra lỗi.
Giai đoạn phát hành cho khách → dùng TRÌNH BIÊN DỊCH.
Lý do một — chạy nhanh hơn. Chương trình đã được dịch sẵn thành mã máy, nên khi khách chạy nó không mất thời gian dịch nữa.
Lý do hai — khách không cần mã nguồn. Trình biên dịch tạo ra một tệp chạy được độc lập. Khách chỉ nhận tệp đó và chạy được ngay, không cần cài trình dịch gì cả.
Lý do ba — bảo vệ mã nguồn. Vì khách chỉ nhận tệp đã dịch, họ không đọc được mã nguồn. Điều này bảo vệ công sức và bí quyết của lập trình viên.
Với trình thông dịch thì ngược lại: khách bắt buộc phải có cả mã nguồn lẫn trình thông dịch mới chạy được.
Kết luận. Hai công cụ không thay thế nhau mà phục vụ hai giai đoạn khác nhau: thông dịch để viết và sửa, biên dịch để giao hàng.
Trong thực tế nhiều môi trường lập trình cung cấp cả hai, đúng vì lý do này.
Ngôn ngữ bậc cao dễ viết hơn nhiều. Giải thích vì sao ngôn ngữ bậc thấp vẫn được dùng trong một số trường hợp, và nêu cái giá phải trả.
Ưu điểm của ngôn ngữ bậc thấp.
Điều khiển phần cứng trực tiếp. Ngôn ngữ bậc thấp cho lập trình viên can thiệp thẳng vào từng thanh ghi, từng ô nhớ và từng chân của bộ xử lý.
Có những việc chỉ làm được như vậy: viết trình điều khiển thiết bị, lập trình vi điều khiển, hay viết phần lõi của hệ điều hành.
Mã nhanh hơn và gọn hơn. Trình biên dịch của ngôn ngữ bậc cao sinh ra mã máy khá tốt nhưng không tối ưu tuyệt đối. Một lập trình viên giỏi viết hợp ngữ tay có thể tạo ra mã nhanh hơn và chiếm ít bộ nhớ hơn.
Điều này quan trọng ở hệ thống nhúng — máy giặt, thiết bị y tế, cảm biến — nơi bộ nhớ chỉ vài ki-lô-byte và từng byte đều quan trọng.
Cái giá phải trả.
Khó viết và dễ sai. Một việc mà ngôn ngữ bậc cao làm trong một dòng có thể cần hàng chục lệnh hợp ngữ. Chương trình dài hơn nhiều nên cơ hội mắc lỗi cũng lớn hơn nhiều.
Khó đọc và khó bảo trì. Mã hợp ngữ rất khó hiểu với người khác — hoặc với chính tác giả sau vài tháng. Việc sửa đổi về sau vì thế tốn kém.
Không khả chuyển. Đây là hạn chế nặng nhất. Ngôn ngữ bậc thấp gắn với một loại bộ xử lý cụ thể. Muốn chạy trên loại máy khác thì phải viết lại gần như từ đầu.
Ngôn ngữ bậc cao chỉ cần dịch lại bằng một trình biên dịch khác là chạy được.
Kết luận. Ngôn ngữ bậc cao không đơn giản là tốt hơn — nó là lựa chọn đúng cho gần như mọi chương trình thông thường.
Ngôn ngữ bậc thấp chỉ đáng dùng ở những nơi hiệu năng hoặc quyền điều khiển phần cứng quan trọng hơn chi phí phát triển: trình điều khiển thiết bị, hệ thống nhúng, và những đoạn mã then chốt về tốc độ.
Đọc xong rồi — làm thử ngay
Bài tập của chương Software gồm 14 câu trắc nghiệm và 5 đề tự luận. Đáp án hiện ngay khi chọn, miễn phí.