Câu trả lời:
inline
hướng dẫn trình biên dịch cố gắng nhúng nội dung hàm vào mã gọi thay vì thực hiện một lệnh gọi thực.
Đối với các chức năng nhỏ được gọi thường xuyên có thể tạo ra sự khác biệt lớn về hiệu suất.
Tuy nhiên, đây chỉ là "gợi ý" và trình biên dịch có thể bỏ qua nó, và hầu hết các trình biên dịch sẽ cố gắng "nội tuyến" ngay cả khi từ khóa không được sử dụng, như một phần của tối ưu hóa, nếu có thể.
ví dụ:
static int Inc(int i) {return i+1};
.... // some code
int i;
.... // some more code
for (i=0; i<999999; i = Inc(i)) {/*do something here*/};
Vòng lặp chặt chẽ này sẽ thực hiện một lệnh gọi hàm trên mỗi lần lặp, và nội dung hàm thực sự ít hơn đáng kể so với mã mà trình biên dịch cần đặt để thực hiện lệnh gọi. inline
về cơ bản sẽ hướng dẫn trình biên dịch chuyển đổi mã trên thành một mã tương đương với:
int i;
....
for (i=0; i<999999; i = i+1) { /* do something here */};
Bỏ qua lệnh gọi hàm thực và quay lại
Rõ ràng đây là một ví dụ để chỉ ra quan điểm, không phải là một đoạn mã thực sự.
static
đề cập đến phạm vi. Trong C, điều đó có nghĩa là hàm / biến chỉ có thể được sử dụng trong cùng một đơn vị dịch.
static
(có hoặc không inline
) có thể ở tiêu đề hoàn toàn tốt, không hiểu lý do gì mà không. Templates là dành cho C ++, câu hỏi này là về C.
inline
là phong cách tốt, imo
inline
không hướng dẫn trình biên dịch thực hiện bất kỳ nỗ lực nào trong nội tuyến. Nó chỉ cho phép lập trình viên bao gồm phần thân hàm trong nhiều đơn vị dịch mà không vi phạm ODR. Một tác dụng phụ của việc này là nó làm cho nó có thể cho trình biên dịch, khi nó sẽ nội tuyến chức năng, để thực sự làm điều này.
Theo mặc định, định nghĩa nội dòng chỉ hợp lệ trong đơn vị dịch hiện tại.
Nếu lớp lưu trữ là extern
, định danh có liên kết bên ngoài và định nghĩa nội tuyến cũng cung cấp định nghĩa bên ngoài.
Nếu là lớp lưu trữ static
, định danh có liên kết nội bộ và định nghĩa nội tuyến là ẩn trong các đơn vị dịch khác.
Nếu lớp lưu trữ không được chỉ định, định nghĩa nội tuyến chỉ hiển thị trong đơn vị dịch hiện tại, nhưng mã định danh vẫn có liên kết bên ngoài và định nghĩa bên ngoài phải được cung cấp trong một đơn vị dịch khác. Trình biên dịch có thể tự do sử dụng định nghĩa nội tuyến hoặc định nghĩa bên ngoài nếu hàm được gọi trong đơn vị dịch hiện tại.
Vì trình biên dịch có thể tự do nội tuyến (và không nội tuyến) bất kỳ hàm nào có định nghĩa hiển thị trong đơn vị dịch hiện tại (và, nhờ tối ưu hóa thời gian liên kết, ngay cả trong các đơn vị dịch khác nhau, mặc dù tiêu chuẩn C không thực sự giải thích đó), đối với hầu hết các mục đích thực tế, không có sự khác biệt giữa static
vàstatic inline
định nghĩa hàm định nghĩa.
Các inline
specifier (như register
storage class) chỉ là một trình biên dịch gợi ý, và trình biên dịch được tự do hoàn toàn bỏ qua nó. Các trình biên dịch không tối ưu hóa tuân thủ tiêu chuẩn chỉ phải tôn trọng các tác dụng phụ của chúng và việc tối ưu hóa các trình biên dịch sẽ thực hiện những tối ưu hóa này có hoặc không có gợi ý rõ ràng.
inline
và register
không phải là vô dụng, tuy nhiên, khi họ chỉ thị cho trình biên dịch để ném lỗi khi các lập trình viên viết code mà sẽ làm cho tối ưu hóa không thể: Một bên ngoài inline
định nghĩa không thể định danh tài liệu tham khảo với liên kết nội bộ (vì đây sẽ là không có sẵn trong một đơn vị dịch thuật khác nhau) hoặc xác định các biến cục bộ có thể sửa đổi với thời lượng lưu trữ tĩnh (vì những biến này sẽ không chia sẻ trạng thái qua các đơn vị dịch) và bạn không thể lấy địa chỉ củaregister
các biến-đủ điều kiện.
Cá nhân tôi cũng sử dụng quy ước để đánh dấu static
các định nghĩa hàm trong tiêu đề inline
, vì lý do chính để đưa các định nghĩa hàm vào tệp tiêu đề là làm cho chúng có thể nhập được.
Nói chung, tôi chỉ sử dụng static inline
các static const
định nghĩa hàm và đối tượng ngoàiextern
khai báo trong tiêu đề.
Tôi chưa bao giờ viết một inline
hàm với một lớp lưu trữ khác với static
.
inline
như thể nó thực sự được áp dụng cho nội tuyến đều gây hiểu lầm và được cho là không chính xác. Không có trình biên dịch hiện đại nào sử dụng nó như một gợi ý để nội dòng hoặc yêu cầu nó để cho phép nội dòng của một hàm.
static
và static inline
. Cả hai đều làm cho định nghĩa vô hình đối với các đơn vị dịch khác. Vì vậy, những gì sẽ là một lý do hợp lý để viết static inline
thay vì static
?
Từ kinh nghiệm của tôi với GCC, tôi biết điều đó static
và static inline
khác ở cách trình biên dịch đưa ra cảnh báo về các chức năng không sử dụng. Chính xác hơn khi bạn khai báo static
hàm và nó không được sử dụng trong đơn vị dịch hiện tại thì trình biên dịch sẽ đưa ra cảnh báo về hàm không sử dụng, nhưng bạn có thể ngăn cảnh báo đó bằng cách thay đổi nó thànhstatic inline
.
Vì vậy, tôi có xu hướng nghĩ rằng static
nên được sử dụng trong các đơn vị dịch và được hưởng lợi từ trình biên dịch kiểm tra bổ sung để tìm các chức năng không sử dụng. Và static inline
nên được sử dụng trong các tệp tiêu đề để cung cấp các chức năng có thể được xếp trong hàng (do không có liên kết bên ngoài) mà không đưa ra cảnh báo.
Thật không may, tôi không thể tìm thấy bất kỳ bằng chứng nào cho logic đó. Ngay cả từ tài liệu GCC, tôi cũng không thể kết luận điều đó inline
ngăn cản các cảnh báo chức năng không sử dụng. Tôi đánh giá cao nếu ai đó sẽ chia sẻ liên kết đến mô tả về điều đó.
warning: unused function 'function' [clang-diagnostic-unused-function]
một static inline
chức năng khi xây dựng với clang-tidy
(v8.0.1), được sử dụng trong một đơn vị dịch khác. Nhưng chắc chắn, đây là một trong những lời giải thích và lý do tốt nhất cho việc kết hợp static
& inline
!
Trong C, static
có nghĩa là hàm hoặc biến bạn xác định chỉ có thể được sử dụng trong tệp này (tức là đơn vị biên dịch)
Vì vậy, static inline
có nghĩa là hàm nội tuyến chỉ có thể được sử dụng trong tệp này.
BIÊN TẬP:
Đơn vị biên dịch phải là Đơn vị dịch
the compile unit
là một cái gì đó tôi đã viết trong báo lỗi, không có những điều như vậy, thuật ngữ thực tế làtranslation unit
Một điểm khác biệt không phải ở cấp độ ngôn ngữ mà là cấp độ triển khai phổ biến: các phiên bản nhất định của gcc sẽ xóa các static inline
hàm không được tham chiếu khỏi đầu ra theo mặc định, nhưng sẽ giữ các static
hàm đơn giản ngay cả khi không được tham chiếu. Tôi không chắc phiên bản này áp dụng cho những phiên bản nào, nhưng từ quan điểm thực tế, nó có nghĩa là bạn nên luôn sử dụng inline
cho các static
hàm trong tiêu đề.
inline
trong định nghĩa? Bạn cũng ngụ ý không sử dụng nó cho các extern
chức năng?
attribute((used))
và việc sử dụng nó để cho phép asm tham chiếu đến các static
hàm và dữ liệu không được tham chiếu khác .
static
đề cập đến phạm vi. Trong C, điều đó có nghĩa là hàm / biến chỉ có thể được sử dụng trong cùng một đơn vị dịch.