6.7.4 Các thông số chức năng
Một tính năng mới của C99: Các inline
từ khóa, chuyển thể từ C ++, là một chức năng-specifier có thể chỉ được sử dụng trong khai báo hàm. Nó hữu ích cho việc tối ưu hóa chương trình yêu cầu định nghĩa của một hàm để hiển thị tại trang web của cuộc gọi. (Lưu ý rằng Tiêu chuẩn không cố gắng chỉ rõ bản chất của những tối ưu hóa này.)
Khả năng hiển thị được đảm bảo nếu hàm có liên kết nội bộ hoặc nếu nó có liên kết bên ngoài và lệnh gọi nằm trong cùng một đơn vị dịch với định nghĩa bên ngoài. Trong những trường hợp này, sự hiện diện của
inline
từ khóa trong khai báo hoặc định nghĩa của hàm không có tác dụng gì ngoài việc chỉ ra tùy chọn rằng các lệnh gọi của hàm đó nên được tối ưu hóa theo sở thích so với các lệnh gọi của các hàm khác được khai báo mà không có inline
từ khóa.
Khả năng hiển thị là một vấn đề đối với lệnh gọi của một hàm có liên kết ngoài trong đó lệnh gọi nằm trong một đơn vị dịch khác với định nghĩa của hàm. Trong trường hợp này, inline
từ khóa cho phép đơn vị dịch có chứa lệnh gọi cũng chứa định nghĩa cục bộ hoặc nội dòng của hàm.
Một chương trình có thể chứa đơn vị dịch với định nghĩa bên ngoài, đơn vị dịch có định nghĩa nội tuyến và đơn vị dịch có khai báo nhưng không có định nghĩa cho một hàm. Các cuộc gọi trong đơn vị dịch sau sẽ sử dụng định nghĩa bên ngoài như bình thường.
Định nghĩa nội tuyến của một hàm được coi là một định nghĩa khác với định nghĩa ngoại vi. Nếu một cuộc gọi đến một số chức năng func
có liên kết bên ngoài xảy ra khi định nghĩa nội tuyến được hiển thị, thì hành vi giống như khi cuộc gọi được thực hiện cho một chức năng khác
__func
với liên kết nội bộ. Một chương trình phù hợp không được phụ thuộc vào hàm nào được gọi. Đây là mô hình nội tuyến trong Tiêu chuẩn.
Một chương trình tuân thủ không được dựa vào việc triển khai bằng định nghĩa nội tuyến, cũng như không được dựa vào việc triển khai bằng định nghĩa bên ngoài. Địa chỉ của một hàm luôn là địa chỉ tương ứng với định nghĩa bên ngoài, nhưng khi địa chỉ này được sử dụng để gọi hàm, định nghĩa nội tuyến có thể được sử dụng. Do đó, ví dụ sau có thể không hoạt động như mong đợi.
inline const char *saddr(void)
{
static const char name[] = "saddr";
return name;
}
int compare_name(void)
{
return saddr() == saddr(); // unspecified behavior
}
Vì việc triển khai có thể sử dụng định nghĩa nội tuyến cho một trong các lệnh gọi đến saddr
và sử dụng định nghĩa bên ngoài cho lệnh gọi kia, nên hoạt động bình đẳng không được đảm bảo đánh giá thành 1 (đúng). Điều này cho thấy rằng các đối tượng tĩnh được xác định trong định nghĩa nội tuyến khác với đối tượng tương ứng của chúng trong định nghĩa bên ngoài. Điều này thúc đẩy ràng buộc chống lại việc xác định một không phải const
đối tượng của loại này.
Nội tuyến đã được thêm vào Tiêu chuẩn theo cách mà nó có thể được triển khai bằng công nghệ trình liên kết hiện có và một tập con nội tuyến C99 tương thích với C ++. Điều này đạt được bằng cách yêu cầu chính xác một đơn vị dịch chứa định nghĩa của một hàm nội tuyến được chỉ định làm đơn vị cung cấp định nghĩa bên ngoài cho hàm. Bởi vì đặc tả đó chỉ bao gồm một khai báo thiếu inline
từ khóa hoặc chứa cả hai inline
và extern
, nó cũng sẽ được chấp nhận bởi trình dịch C ++.
Nội tuyến trong C99 mở rộng đặc tả C ++ theo hai cách. Đầu tiên, nếu một hàm được khai báo
inline
trong một đơn vị dịch, thì nó không cần phải được khai báo inline
trong mọi đơn vị dịch khác. Điều này cho phép, ví dụ, một hàm thư viện được nội tuyến trong thư viện nhưng chỉ có sẵn thông qua một định nghĩa bên ngoài ở nơi khác. Việc thay thế sử dụng một hàm bao bọc cho hàm bên ngoài yêu cầu một tên bổ sung; và nó cũng có thể tác động xấu đến hiệu suất nếu một người dịch không thực sự thay thế nội tuyến.
Thứ hai, yêu cầu rằng tất cả các định nghĩa của một hàm nội tuyến phải "hoàn toàn giống nhau" được thay thế bằng yêu cầu rằng hành vi của chương trình không được phụ thuộc vào việc một lệnh gọi được thực hiện với định nghĩa nội tuyến hiển thị hay định nghĩa bên ngoài, của một chức năng. Điều này cho phép một định nghĩa nội tuyến được chuyên biệt để sử dụng trong một đơn vị dịch cụ thể. Ví dụ: định nghĩa bên ngoài của một hàm thư viện có thể bao gồm một số xác thực đối số không cần thiết cho các lệnh gọi được thực hiện từ các hàm khác trong cùng một thư viện. Những phần mở rộng này cung cấp một số lợi thế; và các lập trình viên lo ngại về tính tương thích có thể chỉ cần tuân theo các quy tắc C ++ chặt chẽ hơn.
Lưu ý rằng việc triển khai cung cấp các định nghĩa nội tuyến về các hàm thư viện chuẩn trong tiêu đề chuẩn là không thích hợp vì điều này có thể phá vỡ một số mã kế thừa khai báo lại các hàm thư viện chuẩn sau khi bao gồm các tiêu đề của chúng. Các inline
từ khóa chỉ nhằm mục đích cung cấp cho người dùng với một cách cầm tay cho thấy nội tuyến chức năng. Bởi vì các tiêu đề tiêu chuẩn không cần phải di động, việc triển khai có các tùy chọn khác dọc theo các dòng:
#define abs(x) __builtin_abs(x)
hoặc các cơ chế không di động khác để nội tuyến các chức năng thư viện tiêu chuẩn.