Để trả lời câu hỏi của bạn, hãy suy nghĩ về các macro được sử dụng chủ yếu cho mục đích gì (Cảnh báo: mã do não biên soạn).
- Macro được sử dụng để xác định các hằng số tượng trưng
#define X 100
Điều này có thể dễ dàng được thay thế bằng: const int X = 100;
- Các macro được sử dụng để xác định (về cơ bản) các hàm không xác định kiểu nội tuyến
#define max(X,Y) (X>Y?X:Y)
Trong bất kỳ ngôn ngữ nào hỗ trợ nạp chồng hàm, điều này có thể được mô phỏng theo cách an toàn hơn nhiều loại bằng cách sử dụng các hàm quá tải đúng loại, hoặc, trong ngôn ngữ hỗ trợ tổng quát, bởi một hàm chung. Macro sẽ vui vẻ cố gắng so sánh bất cứ thứ gì kể cả con trỏ hoặc chuỗi, có thể biên dịch, nhưng gần như chắc chắn không phải là thứ bạn muốn. Mặt khác, nếu bạn thực hiện các loại macro an toàn, chúng không mang lại lợi ích hoặc sự thuận tiện cho các chức năng quá tải.
- Macro được sử dụng để chỉ định các phím tắt cho các yếu tố thường được sử dụng.
#define p printf
Điều này dễ dàng được thay thế bởi một chức năng p()
làm điều tương tự. Điều này khá liên quan đến C (yêu cầu bạn sử dụng va_arg()
họ hàm) nhưng trong nhiều ngôn ngữ khác hỗ trợ số lượng biến đối số của hàm, nó đơn giản hơn nhiều.
Hỗ trợ các tính năng này trong một ngôn ngữ thay vì ngôn ngữ macro đặc biệt đơn giản hơn, ít bị lỗi hơn và ít gây nhầm lẫn hơn cho những người khác đọc mã. Trên thực tế, tôi không thể nghĩ về một trường hợp sử dụng duy nhất cho các macro không thể dễ dàng bị trùng lặp theo một cách khác. Nơi duy nhất mà macro thực sự hữu ích là khi chúng được gắn với các cấu trúc biên dịch có điều kiện như #if
(v.v.).
Vào thời điểm đó, tôi sẽ không tranh luận với bạn, vì tôi tin rằng các giải pháp không tiền xử lý cho việc biên dịch có điều kiện trong các ngôn ngữ phổ biến là cực kỳ cồng kềnh (như tiêm mã byte trong Java). Nhưng các ngôn ngữ như D đã đưa ra các giải pháp không yêu cầu bộ xử lý trước và không cồng kềnh hơn so với sử dụng các điều kiện tiền xử lý, trong khi ít bị lỗi hơn.