Tại sao thư viện C sử dụng macro và hàm có cùng tên?


20

Tôi đang đọc 'Thư viện C tiêu chuẩn' của PJ Plauger, điều này thực sự thú vị. Cuốn sách giải thích không chỉ cách sử dụng thư viện mà còn cả cách thực hiện.

Tôi đã đọc xong ctype.hphần này và trong tiêu đề, các hàm được khai báo là cả hai hàm AND. Ví dụ

int isdigit(int);

nhưng cũng

#define isdigit(c) (_Ctype[(int)(c)] & _DI)

Tôi không hiểu tại sao CẢ HAI được sử dụng?

Ngoài ra, nếu tôi cố gắng tạo lại ctypetiêu đề và triển khai tùy chỉnh của riêng mình , tôi chỉ có thể biên dịch thành công nếu tôi xóa macro (nhận xét định nghĩa).

Khía cạnh này không thực sự được giải thích trong cuốn sách. Ai đó có thể vui lòng giải thích?


Không có gì trong tiêu chuẩn C buộc trình biên dịch phải thực hiện nó dưới dạng macro. Macro rất có thể là dư lượng từ ngày xưa khi C không có nội tuyến. Mặc dù một trình biên dịch thông minh sẽ có thể nội tuyến chức năng đó nếu cần, mà không cần một từ khóa nội tuyến rõ ràng. Vì vậy, macro giống như hàm chỉ có ở đó bởi vì trình biên dịch được thực hiện bởi một người không giỏi trong việc tạo trình biên dịch.

Câu trả lời:


23

Macro là (chính thức) hiệu quả hơn, vì nó không liên quan đến một cuộc gọi chức năng. Nó có thể được tối ưu hóa dễ dàng hơn, vì nó chỉ liên quan đến việc tra cứu bù con trỏ.

Lệnh gọi cho phép liên kết với cùng một thư viện ngay cả khi chương trình được biên dịch mà không có định nghĩa macro - nếu nó được biên dịch với một tiêu đề khác hoặc chỉ với một khai báo giả mạo bên trong tệp nguồn. Ví dụ, nếu bạn có một trình biên dịch có phiên bản ctype.h "được cải tiến" của ai đó mà không có macro, hàm vẫn sẽ tồn tại trong thời gian chạy để sử dụng.

Nếu chúng ta nhìn vào tiêu chuẩn:

7.1.4 Sử dụng các chức năng của thư viện

Bất kỳ chức năng nào được khai báo trong tiêu đề đều có thể được triển khai bổ sung dưới dạng macro giống như chức năng trong tiêu đề, do đó, nếu chức năng thư viện được khai báo rõ ràng khi bao gồm tiêu đề của nó, có thể sử dụng một trong các kỹ thuật được hiển thị bên dưới để đảm bảo không khai báo bị ảnh hưởng bởi một vĩ mô như vậy. Bất kỳ định nghĩa vĩ mô nào của hàm đều có thể bị loại bỏ cục bộ bằng cách đặt tên của hàm trong ngoặc đơn, vì tên này sau đó không được đặt theo dấu ngoặc đơn bên trái cho biết mở rộng tên hàm macro. Với cùng một lý do cú pháp, nó được phép lấy địa chỉ của hàm thư viện ngay cả khi nó cũng được định nghĩa là một macro.

Điều đó có nghĩa là nếu bạn viết:

int b = (isdigit)(c);

hoặc là

int (*f)(int) = &isdigit;
int b = f(c);

sau đó bạn đang gọi hàm thực tế, không phải macro. Bạn cũng có thể viết hợp pháp:

#undef isdigit
int b = isdigit(c);

hoặc (trong tệp nguồn không có #include <ctype.h>trực tiếp hoặc quá cảnh):

extern int isdigit(int);
int b = isdigit(c);

Làm thế nào chương trình có thể được biên dịch mà KHÔNG có định nghĩa vĩ mô?
dùng619818

@ user619818 sử dụng extern int isdigit(int), ví dụ.
ecatmur

Để tôi rõ ràng, ý bạn là người dùng không có #include <anything> mà thay vào đó thêm int isdigit (int); ở đầu tập tin thực hiện. OK, chỉ cần đọc qua phản ứng của bạn đúng cách.
dùng619818

Có chức năng có thể gọi được (so với mã macro được nội tuyến) cũng cho phép các ngôn ngữ khác như python và perl giao tiếp với các chức năng đó
technosaurus 15/03/2016
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.