Khi nào tôi nên viết từ khóa 'nội tuyến' cho một chức năng / phương thức?


562

Khi nào tôi nên viết từ khóa inlinecho một hàm / phương thức trong C ++?

Sau khi thấy một số câu trả lời, một số câu hỏi liên quan:

  • Khi nào tôi không nên viết từ khóa 'nội tuyến' cho một hàm / phương thức trong C ++?

  • Khi nào trình biên dịch sẽ không biết khi nào thực hiện một hàm / phương thức 'nội tuyến'?

  • Có vấn đề gì không nếu một ứng dụng được đa luồng khi một người viết 'nội tuyến' cho một chức năng / phương thức?


40
Nếu bạn xác định một chức năng trong một tiêu đề, bạn sẽ cần khai báo nội tuyến. Nếu không, bạn sẽ nhận được lỗi liên kết về nhiều định nghĩa của hàm.
Martin York

15
@Martin: Trừ khi nó theo định nghĩa lớp, phải kén chọn.
David Thornley

20
@David: Để thêm kén chọn, điều đó chỉ bởi vì các chức năng như vậy được đánh dấu ngầm inline(9.3 / 2).
Các cuộc đua nhẹ nhàng trong quỹ đạo


Đồng thời xem Hàm nội tuyến trong Câu hỏi thường gặp về C ++. Họ có một điều trị rất tốt của nội tuyến.
19 lúc 3:30

Câu trả lời:


882

Ôi trời, một trong những thú cưng của tôi.

inlinelà giống statichoặc externhơn là một lệnh cho trình biên dịch nội tuyến các chức năng của bạn. extern, static, inlineLà chỉ thị liên kết, sử dụng gần như độc quyền bởi các mối liên kết, không phải là trình biên dịch.

Người ta nói rằng inlinegợi ý cho trình biên dịch mà bạn nghĩ rằng hàm nên được nội tuyến. Điều đó có thể đúng vào năm 1998, nhưng một thập kỷ sau, trình biên dịch không cần gợi ý như vậy. Chưa kể con người thường sai khi tối ưu hóa mã, vì vậy hầu hết các trình biên dịch đều bỏ qua 'gợi ý'.

  • static- tên biến / hàm không thể được sử dụng trong các đơn vị dịch thuật khác. Trình liên kết cần đảm bảo rằng nó không vô tình sử dụng biến / hàm được xác định tĩnh từ một đơn vị dịch thuật khác.

  • extern- sử dụng tên biến / hàm này trong đơn vị dịch này nhưng không phàn nàn nếu nó không được xác định. Trình liên kết sẽ sắp xếp nó ra và đảm bảo tất cả các mã đã cố sử dụng một số biểu tượng bên ngoài có địa chỉ của nó.

  • inline- chức năng này sẽ được xác định trong nhiều đơn vị dịch thuật, đừng lo lắng về nó. Trình liên kết cần đảm bảo tất cả các đơn vị dịch sử dụng một thể hiện duy nhất của biến / hàm.

Lưu ý: Nói chung, khai báo mẫu inlinelà vô nghĩa, vì chúng có ngữ nghĩa liên kết inlineđã có. Tuy nhiên, chuyên môn hóa rõ ràng và khởi tạo các mẫu yêu cầuinline phải được sử dụng.


Câu trả lời cụ thể cho câu hỏi của bạn:

  • Khi nào tôi nên viết từ khóa 'nội tuyến' cho một hàm / phương thức trong C ++?

    Chỉ khi bạn muốn chức năng được xác định trong một tiêu đề. Chính xác hơn chỉ khi định nghĩa của hàm có thể hiển thị trong nhiều đơn vị dịch. Bạn nên xác định các hàm nhỏ (như trong một lớp lót) trong tệp tiêu đề vì nó cung cấp cho trình biên dịch nhiều thông tin hơn để làm việc trong khi tối ưu hóa mã của bạn. Nó cũng làm tăng thời gian biên dịch.

  • Khi nào tôi không nên viết từ khóa 'nội tuyến' cho một hàm / phương thức trong C ++?

    Đừng thêm nội tuyến chỉ vì bạn nghĩ rằng mã của bạn sẽ chạy nhanh hơn nếu trình biên dịch nội tuyến.

  • Khi nào trình biên dịch sẽ không biết khi nào thực hiện một hàm / phương thức 'nội tuyến'?

    Nói chung, trình biên dịch sẽ có thể làm điều này tốt hơn bạn. Tuy nhiên, trình biên dịch không có tùy chọn mã nội tuyến nếu nó không có định nghĩa hàm. Trong mã được tối ưu hóa tối đa thường tất cả các privatephương thức được nội tuyến cho dù bạn có yêu cầu hay không.

    Để tránh nội tuyến trong GCC, hãy sử dụng __attribute__(( noinline ))và trong Visual Studio, sử dụng __declspec(noinline).

  • Có vấn đề gì không nếu một ứng dụng được đa luồng khi một người viết 'nội tuyến' cho một chức năng / phương thức?

    Đa luồng không ảnh hưởng đến nội tuyến theo bất kỳ cách nào.


172
+1 Mô tả hay nhất về nội tuyến tôi đã thấy trong ... (mãi mãi). Bây giờ tôi sẽ tách bạn ra và sử dụng nó trong tất cả các giải thích của tôi về từ khóa nội tuyến.
Martin York

6
@Ziggy, điều tôi đã cố gắng nói là trình biên dịch nội tuyến và inlinetừ khóa không liên quan. Bạn đã có ý tưởng đúng mặc dù. Theo quy định, việc đoán những gì sẽ được cải thiện bằng cách đặt nội tuyến là rất dễ xảy ra lỗi. Ngoại lệ cho quy tắc đó là một lót.
deft_code

4
Câu trả lời này làm tôi bối rối một chút. Bạn nói tất cả những gì về trình biên dịch có thể nội tuyến / không nội tuyến tốt hơn. Sau đó, bạn nói rằng bạn nên đặt một lớp lót / hàm nhỏ trong tiêu đề và trình biên dịch không thể mã nội tuyến mà không có định nghĩa hàm. Không phải là một chút mâu thuẫn? Tại sao không chỉ đặt mọi thứ trong tệp cpp và để trình biên dịch quyết định?
dùng673679

5
Trình biên dịch sẽ chỉ gọi các hàm nội tuyến trong đó định nghĩa có sẵn tại trang web cuộc gọi. Rời khỏi tất cả các chức năng trong tệp cpp sẽ giới hạn nội tuyến cho tệp đó. Tôi đề nghị xác định một dòng nhỏ trong dòng trong .h vì chi phí cho tốc độ biên dịch là không đáng kể và bạn gần như đảm bảo trình biên dịch sẽ thực hiện cuộc gọi. Quan điểm của tôi về trình biên dịch nội tuyến là nó là cổng của nghệ thuật tối ưu hóa, tại đó trình biên dịch của bạn tốt hơn nhiều so với bạn.
deft_code

8
Bất cứ khi nào tôi đọc một cái gì đó vào tài khoản về kiến thức tích lũy của internet, tôi phải nghĩ đến câu nói nổi tiếng của John Lawton: Điều trớ trêu của Thời đại Thông tin là nó đã mang lại sự tôn trọng mới cho ý kiến ​​không hiểu biết.
IInspectable

60

Tôi muốn đóng góp cho tất cả các câu trả lời tuyệt vời trong chủ đề này với một ví dụ thuyết phục để phân tán mọi hiểu lầm còn lại.

Cho hai tệp nguồn, chẳng hạn như:

  • nội tuyến11.cpp:

    #include <iostream>
    
    void bar();
    
    inline int fun() {
      return 111;
    }
    
    int main() {
      std::cout << "inline111: fun() = " << fun() << ", &fun = " << (void*) &fun;
      bar();
    }
  • nội tuyến 222.cpp:

    #include <iostream>
    
    inline int fun() {
      return 222;
    }
    
    void bar() {
      std::cout << "inline222: fun() = " << fun() << ", &fun = " << (void*) &fun;
    }

  • Trường hợp A:

    Biên dịch :

    g++ -std=c++11 inline111.cpp inline222.cpp

    Đầu ra :

    inline111: fun() = 111, &fun = 0x4029a0
    inline222: fun() = 111, &fun = 0x4029a0

    Thảo luận :

    1. Ngay cả bạn nên có các định nghĩa giống hệt nhau về các hàm nội tuyến của mình, trình biên dịch C ++ không gắn cờ nếu đó không phải là trường hợp (thực tế, do quá trình biên dịch riêng biệt nên không có cách nào để kiểm tra). Đó là nhiệm vụ của riêng bạn để đảm bảo điều này!

    2. Trình liên kết không phàn nàn về Quy tắc Một Định nghĩa , như fun()được khai báo là inline. Tuy nhiên, bởi vì inline111.cpp là đơn vị dịch đầu tiên (thực sự gọi fun()) được xử lý bởi trình biên dịch, trình biên dịch sẽ khởi tạo cuộc gặp gỡ cuộc gọi đầu tiênfun() của nó trong inline111.cpp . Nếu trình biên dịch quyết định không mở rộng theo cuộc gọi của nó từ bất kỳ nơi nào khác trong chương trình của bạn ( ví dụ: từ inline 222.cpp ), cuộc gọi đến sẽ luôn được liên kết với phiên bản của nó được tạo ra từ inline111.cpp (cuộc gọi đến bên trong inline 222.cppfun()fun()fun()cũng có thể tạo một thể hiện trong đơn vị dịch thuật đó, nhưng nó sẽ vẫn không được liên kết). Thật vậy, điều đó là hiển nhiên từ &fun = 0x4029a0bản in giống hệt nhau .

    3. Cuối cùng, mặc dù inlinegợi ý cho trình biên dịch để thực sự mở rộng lớp lót fun(), nó hoàn toàn bỏ qua đề xuất của bạn, điều này rõ ràng bởi vì fun() = 111trong cả hai dòng.


  • Trường hợp B:

    Biên dịch (thông báo ngược thứ tự) :

    g++ -std=c++11 inline222.cpp inline111.cpp

    Đầu ra :

    inline111: fun() = 222, &fun = 0x402980
    inline222: fun() = 222, &fun = 0x402980

    Thảo luận :

    1. Trường hợp này khẳng định những gì đã được thảo luận trong trường hợp một .

    2. Lưu ý một điểm quan trọng, đó là nếu bạn nhận xét cuộc gọi thực tế đến fun()trong nội tuyến 222.cpp ( ví dụ: hoàn toàn bình luận couttrong nội tuyến 222.cpp ), mặc dù thứ tự biên dịch của các đơn vị dịch thuật của bạn, fun()sẽ được thực hiện ngay khi gặp cuộc gọi đầu tiên trong nội tuyến11.cpp , dẫn đến in ra cho Trường hợp Binline111: fun() = 111, &fun = 0x402980.


  • Trường hợp C:

    Biên dịch (thông báo -O2) :

    g++ -std=c++11 -O2 inline222.cpp inline111.cpp

    hoặc là

    g++ -std=c++11 -O2 inline111.cpp inline222.cpp

    Đầu ra :

    inline111: fun() = 111, &fun = 0x402900
    inline222: fun() = 222, &fun = 0x402900

    Thảo luận :

    1. Như được mô tả ở đây , -O2tối ưu hóa khuyến khích trình biên dịch thực sự mở rộng các chức năng có thể được nội tuyến (Thông báo cũng -fno-inlinemặc định mà không có tùy chọn tối ưu hóa). Như đã thấy rõ từ bản in ở đây, fun()thực tế đã được mở rộng nội tuyến (theo định nghĩa của nó trong đơn vị dịch cụ thể đó ), dẫn đến hai bản in khác nhau fun() . Mặc dù vậy, vẫn chỉ có một trường hợp được liên kết toàn cầu fun()(theo yêu cầu của tiêu chuẩn), như hiển nhiên từ bản in giống hệt nhau &fun .

8
Câu trả lời của bạn là một bài viết minh họa về lý do tại sao ngôn ngữ làm cho các inlinechức năng đó trở thành hành vi không xác định.
R Sahu

Bạn cũng nên thêm các trường hợp biên dịch và liên kết là riêng biệt, với mỗi trường hợp là .cppđơn vị dịch thuật riêng của nó. Tốt hơn là, thêm các trường hợp cho -fltophép / vô hiệu hóa.
syockit

Tham chiếu C ++ rõ ràng là "Nếu một hàm hoặc biến nội tuyến (kể từ C ++ 17) có liên kết ngoài được định nghĩa khác nhau trong các đơn vị dịch khác nhau, thì hành vi không được xác định." Vì vậy, những thứ bạn viết là cụ thể của GCC vì nó là tác dụng phụ của việc phối hợp các quá trình biên dịch và liên kết. Ngoài ra, lưu ý rằng điều này có thể khác nhau giữa các phiên bản.
Petr Fiedler

27

Bạn vẫn cần nội tuyến rõ ràng chức năng của mình khi thực hiện chuyên môn hóa mẫu (nếu chuyên môn hóa nằm trong tệp .h)


21

1) Ngày nay, khá nhiều không bao giờ. Nếu đó là một ý tưởng tốt để nội tuyến một chức năng, trình biên dịch sẽ thực hiện nó mà không cần sự giúp đỡ của bạn.

2) Luôn luôn. Xem # 1.

(Đã chỉnh sửa để phản ánh rằng bạn đã chia câu hỏi của mình thành hai câu hỏi ...)


Đúng. Nội tuyến chỉ là một gợi ý cho trình biên dịch, và nó miễn phí để bỏ qua bạn. Ngày nay, trình biên dịch có thể biết rõ hơn lập trình viên những chức năng nào là tốt nhất để nội tuyến.
Mark Byers

1
Có, nhưng nó ít liên quan hơn - để một hàm được nội tuyến, phần thân của nó phải nằm trong cùng một đơn vị biên dịch (ví dụ: trong một tiêu đề). Điều đó ít phổ biến hơn trong các chương trình C.
Michael Kohne

1
xác định mẫu hàm không phải thành viên (còn gọi là mẫu hàm không tĩnh) không yêu cầu nội tuyến. Xem một quy tắc định nghĩa (3.2 / 5).
deft_code

2
-1: inlinevẫn cần thiết, ví dụ để xác định hàm trong tệp tiêu đề (và điều đó là bắt buộc để nội tuyến một hàm như vậy trong một số đơn vị biên dịch).
Melebius

1
@ Étienne đó là cụ thể thực hiện. Theo tiêu chuẩn, có một Quy tắc Định nghĩa, có nghĩa là ở đây, nếu bạn ngây thơ đưa định nghĩa hàm vào nhiều đơn vị dịch, bạn sẽ gặp lỗi. Nhưng nếu chức năng đó có trình inlinexác định, các thể hiện của nó được tự động thu gọn thành một bởi trình liên kết và ODR không được sử dụng.
Ruslan

12

Khi nào tôi không nên viết từ khóa 'nội tuyến' cho một hàm / phương thức trong C ++?

Nếu chức năng được khai báo trong tiêu đề và được xác định trong .cpptệp, bạn không nên viết từ khóa.

Khi nào trình biên dịch sẽ không biết khi nào thực hiện một hàm / phương thức 'nội tuyến'?

Không có tình huống như vậy. Trình biên dịch không thể tạo ra một hàm nội tuyến. Tất cả những gì nó có thể làm là nội tuyến một số hoặc tất cả các cuộc gọi đến chức năng. Nó không thể làm như vậy nếu nó không có mã của hàm (trong trường hợp đó, trình liên kết cần phải làm điều đó nếu nó có thể làm như vậy).

Có vấn đề gì không nếu một ứng dụng được đa luồng khi một người viết 'nội tuyến' cho một chức năng / phương thức?

Không, điều đó không quan trọng.


Có những trường hợp thích hợp sử dụng nội tuyến trong tệp .cpp. Ví dụ, áp dụng tối ưu hóa cho mã hoàn toàn cụ thể thực hiện.
Robin Davies

@RobinDavies cập nhật câu trả lời. Có vẻ như bạn đã hiểu nhầm những gì tôi muốn viết.
Julian Schaub - litb

5
  • Khi nào trình biên dịch sẽ không biết khi nào thực hiện một hàm / phương thức 'nội tuyến'?

Điều này phụ thuộc vào trình biên dịch được sử dụng. Đừng tin tưởng một cách mù quáng rằng ngày nay các trình biên dịch biết rõ hơn con người làm thế nào để nội tuyến và bạn không bao giờ nên sử dụng nó vì lý do hiệu suất, bởi vì đó là chỉ thị liên kết thay vì gợi ý tối ưu hóa. Trong khi tôi đồng ý rằng về mặt ý thức hệ thì những lập luận này gặp phải thực tế có thể là một điều khác.

Sau khi đọc nhiều luồng xung quanh, tôi đã cố gắng tò mò về tác động của nội tuyến đối với mã Tôi chỉ đang làm việc và kết quả là tôi đã tăng tốc độ cho GCC và không tăng tốc cho trình biên dịch Intel.

(Chi tiết hơn: mô phỏng toán học với một số hàm quan trọng được xác định bên ngoài lớp, GCC 4.6.3 (g ++ -O3), ICC 13.1.0 (icpc -O3); thêm nội tuyến vào các điểm quan trọng gây ra tăng tốc 6% với mã GCC).

Vì vậy, nếu bạn đủ điều kiện GCC 4.6 làm trình biên dịch hiện đại, kết quả là chỉ thị nội tuyến vẫn có vấn đề nếu bạn viết các tác vụ chuyên sâu của CPU và biết chính xác nút thắt ở đâu.


6
Tôi muốn xem thêm bằng chứng để sao lưu các yêu cầu của bạn. Vui lòng cung cấp mã bạn đang kiểm tra cũng như đầu ra của trình biên dịch có và không có từ khóa nội tuyến. Bất kỳ số lượng điều có thể đã mang lại cho bạn lợi ích hiệu suất.
void.pulum

1
Cuối cùng, một người không chỉ lặp lại những gì người khác nói, nhưng thực sự xác minh những tuyên bố đó. Gcc thực sự vẫn coi từ khóa nội tuyến là một gợi ý (tôi nghĩ clang bỏ qua nó hoàn toàn).
MikeMB

@ void.pulum: Tại sao điều này quá khó tin? Nếu tối ưu hóa đã hoàn hảo, thì các phiên bản mới không thể cải thiện hiệu suất chương trình. Nhưng họ thường xuyên làm.
MikeMB

3

Trong thực tế, khá nhiều không bao giờ. Tất cả những gì bạn đang làm là đề xuất rằng trình biên dịch tạo một hàm nhất định nội tuyến (ví dụ: thay thế tất cả các lệnh gọi đến hàm này / w phần thân của nó). Tất nhiên, không có gì đảm bảo: trình biên dịch có thể bỏ qua lệnh này.

Trình biên dịch nói chung sẽ làm tốt công việc phát hiện + tối ưu hóa những thứ như thế này.


7
Vấn đề là inlinecó sự khác biệt về ngữ nghĩa trong C ++ (ví dụ: theo cách xử lý nhiều định nghĩa), điều này rất quan trọng trong một số trường hợp (ví dụ: mẫu).
Pavel Minaev

4
nội tuyến được sử dụng để giải quyết các trường hợp trong đó một biểu tượng có nhiều định nghĩa. Mẫu tuy nhiên đã được xử lý bởi ngôn ngữ. Một ngoại lệ là một hàm mẫu chuyên dụng không còn bất kỳ tham số mẫu nào nữa (mẫu <>). Chúng được coi giống như các hàm hơn các mẫu và vì vậy cần từ khóa nội tuyến để liên kết.
deft_code

2

gcc theo mặc định không nội tuyến bất kỳ chức năng nào khi biên dịch mà không kích hoạt tối ưu hóa. Tôi không biết về studio hình ảnh - deft_code

Tôi đã kiểm tra điều này cho Visual Studio 9 (15.00.30729.01) bằng cách biên dịch với / FAcs và xem mã lắp ráp: Trình biên dịch tạo ra các cuộc gọi đến các chức năng thành viên mà không được tối ưu hóa trong chế độ gỡ lỗi . Ngay cả khi chức năng được đánh dấu bằng __forceinline , không có mã thời gian chạy nội tuyến nào được tạo ra.


1
Cho phép / Tường được thông báo về chức năng nào được đánh dấu nội tuyến nhưng thực tế không được nội tuyến
paulm

0

Bạn muốn đặt nó ngay từ đầu, trước khi trả về loại. Nhưng hầu hết các Trình biên dịch bỏ qua nó. Nếu nó được định nghĩa và nó có một khối mã nhỏ hơn, hầu hết các trình biên dịch đều coi nó là nội tuyến.


0

Trừ khi bạn đang viết thư viện hoặc có lý do đặc biệt, bạn có thể quên inlinevà sử dụng tối ưu hóa thời gian liên kết thay thế. Nó loại bỏ yêu cầu rằng một định nghĩa hàm phải nằm trong một tiêu đề để nó được xem xét để nội tuyến trên các đơn vị biên dịch, đó chính xác là những gì inlinecho phép.

(Nhưng hãy xem Có lý do nào để không sử dụng tối ưu hóa thời gian liên kết không? )


0

Nội tuyếnTừ khóa yêu cầu trình biên dịch thay thế lời gọi hàm bằng phần thân của hàm, trước tiên nó đánh giá biểu thức và sau đó chuyển qua. Nó làm giảm chi phí gọi hàm vì không cần lưu trữ địa chỉ trả về và không cần bộ nhớ ngăn xếp cho hàm tranh luận.

Khi nào nên sử dụng:

  • Để cải thiện hiệu suất
  • Để giảm chi phí cuộc gọi.
  • Vì nó chỉ là một yêu cầu cho trình biên dịch, một số hàm nhất định sẽ không được nội tuyến * các hàm lớn
    • các hàm có quá nhiều đối số có điều kiện
    • mã đệ quy và mã với các vòng lặp, vv

Nó có thể có lợi cho bạn để biết rằng đây thực sự không phải là trường hợp. Mức tối ưu hóa -O0 đến - Ofast là yếu tố quyết định liệu một hàm có được nội tuyến hay không. Nội tuyến trên biên dịch thông thường (-O0) sẽ không nội tuyến một hàm bất kể bạn có sử dụng inlinehay không trong C và C ++. C Inline: stackoverflow.com/a/62287072/7194773 C ++ nội tuyến: stackoverflow.com/a/62230963/7194773
Lewis Kelsey

0

C ++ nội tuyến hoàn toàn khác với C nội tuyến .

#include <iostream>
extern inline int i[];
int i [5];
struct c {
  int function (){return 1;} //implicitly inline
  static inline int j = 3; //explicitly inline
};
int main() {
  c j;
  std::cout << i;
}

inlinetự nó ảnh hưởng đến trình biên dịch, trình biên dịch và trình liên kết. Đó là một chỉ thị cho trình biên dịch nói rằng chỉ phát ra một biểu tượng cho chức năng / dữ liệu này nếu nó được sử dụng trong đơn vị dịch thuật và nếu nó giống như các phương thức lớp, hãy nói với trình biên dịch lưu trữ chúng trong phần .section .text.c::function(),"axG",@progbits,c::function(),comdathoặc .section .bss.i,"awG",@nobits,i,comdatcho dữ liệu.

Điều này sau đây .section name, "flags"MG, @type, entsize, GroupName[, linkage]. Ví dụ, tên phần là .text.c::function(). axGcó nghĩa là phần này có thể được phân bổ, thực thi và trong một nhóm, tức là tên nhóm sẽ được chỉ định (và không có cờ M nên sẽ không chỉ định kích thước); @progbitscó nghĩa là phần chứa dữ liệu và không trống; liên kết có nghĩa là trong tất cả các tệp đối tượng, tất cả các phần gặp phải với tên nhóm được gắn thẻ comdat này sẽ bị xóa khỏi tệp thực thi cuối cùng ngoại trừ 1, tức là trình biên dịch đảm bảo rằng chỉ có một định nghĩa trong đơn vị dịch thuật và sau đó báo cho trình biên dịch mã đặt nó trong nhóm riêng của nó trong tệp đối tượng (1 phần trong 1 nhóm) và sau đó trình liên kết sẽ đảm bảo rằng nếu bất kỳ tệp đối tượng nào có một nhóm có cùng tên, thì chỉ bao gồm một trong .exe cuối cùng. Sự khác biệt giữac::function()là tên nhóm và nhóm cócomdatinlinevà không sử dụng inlinehiện được hiển thị cho trình biên dịch chương trình và kết quả là trình liên kết, bởi vì nó không được lưu trữ trong thường xuyên .datahoặc.text vv do các lệnh của chúng.

static inlinetrong một lớp có nghĩa là nó là một định nghĩa kiểu và không khai báo (cho phép thành viên tĩnh được định nghĩa trong lớp) và làm cho nó thành dòng; bây giờ nó hành xử như trên.

static inlinetại phạm vi tập tin chỉ ảnh hưởng đến trình biên dịch. Nó có nghĩa là trình biên dịch: chỉ phát ra một biểu tượng cho chức năng / dữ liệu này nếu nó được sử dụng trong đơn vị dịch và làm như một biểu tượng tĩnh thông thường (lưu trữ in.text /.data mà không có lệnh .globl). Đối với trình biên dịch, bây giờ không có sự khác biệt giữa staticstatic inline

extern inlinelà một khai báo có nghĩa là bạn phải xác định ký hiệu này trong đơn vị dịch hoặc lỗi trình biên dịch; nếu nó được định nghĩa thì hãy coi nó như một trình biên dịch thông thường inlinevà trình biên dịch chương trình và trình liên kết sẽ không có sự khác biệt giữa extern inlineinlinevì vậy đây chỉ là một trình bảo vệ trình biên dịch.

extern inline int i[];
extern int i[]; //allowed repetition of declaration with incomplete type, inherits inline property
extern int i[5]; //declaration now has complete type
extern int i[5]; //allowed redeclaration if it is the same complete type or has not yet been completed
extern int i[6]; //error, redeclaration with different complete type
int i[5]; //definition, must have complete type and same complete type as the declaration if there is a declaration with a complete type

Toàn bộ ở trên mà không có dòng lỗi sụp đổ đến inline int i[5]. Rõ ràng nếu bạn đã làm extern inline int i[] = {5};thìextern sẽ bị bỏ qua do định nghĩa rõ ràng thông qua chuyển nhượng.

inlinetrên một không gian tên, xem cái nàycái này


-1

Khi phát triển và gỡ lỗi mã, hãy bỏ inlinequa. Nó phức tạp gỡ lỗi.

Lý do chính để thêm chúng là để giúp tối ưu hóa mã được tạo. Thông thường, giao dịch này tăng không gian mã cho tốc độ, nhưng đôi khi inlinetiết kiệm cả không gian mã và thời gian thực hiện.

Mong đợi loại suy nghĩ này về tối ưu hóa hiệu suất trước khi hoàn thành thuật toán là tối ưu hóa sớm .


12
inlinecác hàm thường không được nội tuyến trừ khi biên dịch với tối ưu hóa, vì vậy chúng không ảnh hưởng đến việc gỡ lỗi theo bất kỳ cách nào. Hãy nhớ rằng đó là một gợi ý, không phải là một nhu cầu.
Pavel Minaev

3
gcc theo mặc định không nội tuyến bất kỳ chức năng nào khi biên dịch mà không kích hoạt tối ưu hóa. Tôi không biết về studio hình ảnh
deft_code

Tôi đã làm việc với một dự án g ++ khổng lồ có bật gỡ lỗi. Có thể các tùy chọn khác đã ngăn chặn nó, nhưng các inlinechức năng đã được nội tuyến. Không thể thiết lập một điểm dừng có ý nghĩa trong đó.
wallyk

2
cho phép gỡ lỗi không dừng nội tuyến trong gcc. Nếu bất kỳ tối ưu hóa nào được kích hoạt (-O1 trở lên), thì gcc sẽ cố gắng nội tuyến các trường hợp rõ ràng nhất. Theo truyền thống, GDB đã có một thời gian khó khăn với các điểm dừng và các nhà xây dựng, đặc biệt là các nhà xây dựng nội tuyến. Nhưng, điều đó đã được sửa trong các phiên bản gần đây (ít nhất là 6,7, có thể sớm hơn).
deft_code

2
Việc thêm inlinesẽ không làm gì để cải thiện mã trên một trình biên dịch hiện đại, điều này có thể tìm ra liệu có nên tự nội tuyến hay không.
David Thornley

-1

Khi một người nên nội tuyến:

1.Khi người ta muốn tránh các chi phí xảy ra khi chức năng được gọi như truyền tham số, truyền điều khiển, trả về điều khiển, v.v.

2. Hàm này phải nhỏ, thường xuyên được gọi và tạo nội tuyến thực sự có lợi vì theo quy tắc 80-20, hãy cố gắng làm cho các hàm đó có ảnh hưởng lớn đến hiệu suất chương trình.

Như chúng ta biết rằng nội tuyến chỉ là một yêu cầu trình biên dịch tương tự như đăng ký và nó sẽ khiến bạn phải trả giá ở kích thước mã Object.


"Nội tuyến chỉ là một yêu cầu trình biên dịch tương tự như đăng ký" Chúng tương tự nhau vì không phải là yêu cầu hoặc không liên quan gì đến tối ưu hóa. inlineđã mất trạng thái như một gợi ý tối ưu hóa và hầu hết các trình biên dịch chỉ sử dụng nó để tạo ra các khoản phụ cấp cho nhiều định nghĩa - như IMO họ nên làm. Hơn nữa, vì C ++ 11, registerđã hoàn toàn không được chấp nhận vì ý nghĩa trước đó của nó là 'Tôi biết rõ hơn trình biên dịch cách tối ưu hóa': giờ đây nó chỉ là một từ dành riêng không có nghĩa hiện tại.
gạch dưới

@underscore_d: Gcc vẫn lắng nghe inlineở một mức độ nào đó.
MikeMB

-1

Hàm nội tuyến C ++ là khái niệm mạnh mẽ thường được sử dụng với các lớp. Nếu một hàm là nội tuyến, trình biên dịch sẽ đặt một bản sao mã của hàm đó tại mỗi điểm mà hàm được gọi tại thời điểm biên dịch.

Bất kỳ thay đổi nào đối với hàm nội tuyến đều có thể yêu cầu tất cả các máy khách của hàm được biên dịch lại bởi vì trình biên dịch sẽ cần thay thế tất cả mã một lần nữa nếu không nó sẽ tiếp tục với chức năng cũ.

Để nội tuyến một chức năng, đặt từ khóa nội tuyến trước tên chức năng và xác định chức năng trước khi bất kỳ cuộc gọi nào được thực hiện cho chức năng. Trình biên dịch có thể bỏ qua vòng loại nội tuyến trong trường hợp hàm được xác định là nhiều hơn một dòng.

Một định nghĩa hàm trong định nghĩa lớp là một định nghĩa hàm nội tuyến, ngay cả khi không sử dụng bộ xác định nội tuyến.

Dưới đây là một ví dụ, sử dụng hàm nội tuyến để trả về tối đa hai số

#include <iostream>

using namespace std;

inline int Max(int x, int y) { return (x > y)? x : y; }

// Main function for the program
int main() {
   cout << "Max (100,1010): " << Max(100,1010) << endl;

   return 0;
}

để biết thêm thông tin xem tại đây .

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.