2009-07-16 28 views
93

Hàm nội tuyến khác với macro tiền xử lý như thế nào?Các chức năng nội dòng và các macro tiền xử lý

+3

Tôi gắn cờ đây là bài tập về nhà, mặc dù đây có thể là câu hỏi hợp pháp. Cho đến nay tất cả các câu hỏi của bạn đều giống như các câu hỏi về bài tập về nhà và một trong số chúng được đóng lại như vậy. –

+0

Câu trả lời cho http://stackoverflow.com/questions/132738/why-should-i-ever-use-inline-code chứa một số thông tin liên quan đến câu hỏi của bạn. –

Trả lời

108

Macro tiền xử lý chỉ là các mẫu thay thế được áp dụng cho mã của bạn. Chúng có thể được sử dụng hầu như bất cứ nơi nào trong mã của bạn bởi vì chúng được thay thế bằng các mở rộng của chúng trước khi bắt đầu bất kỳ biên dịch nào.

Chức năng nội tuyến là các chức năng thực tế có nội dung được đưa trực tiếp vào trang web cuộc gọi của họ. Chúng chỉ có thể được sử dụng khi một cuộc gọi hàm thích hợp.

Bây giờ, theo như sử dụng các macro vs chức năng nội tuyến trong một bối cảnh chức năng giống như, lưu ý rằng:

  • Macros không gõ an toàn, và có thể được mở rộng bất kể họ là syntatically chính xác - giai đoạn biên dịch sẽ báo cáo lỗi do các vấn đề mở rộng macro.
  • Macro có thể được sử dụng trong ngữ cảnh bạn không mong đợi, dẫn đến các sự cố
  • Macro linh hoạt hơn, ở chỗ chúng có thể mở rộng các macro khác - trong khi các hàm nội tuyến không nhất thiết phải thực hiện điều này.
  • Macro có thể gây ra các tác dụng phụ do mở rộng của chúng, vì các biểu thức nhập được sao chép bất cứ nơi nào chúng xuất hiện trong mẫu.
  • Chức năng nội tuyến không phải lúc nào cũng được đảm bảo được gạch chân - một số trình biên dịch chỉ thực hiện việc này trong bản phát hành hoặc khi chúng được cấu hình cụ thể để làm như vậy. Ngoài ra, trong một số trường hợp nội tuyến có thể không thực hiện được.
  • Chức năng nội tuyến có thể cung cấp phạm vi cho các biến (đặc biệt là các biến tĩnh), các macro tiền xử lý chỉ có thể thực hiện điều này trong các khối mã {...} và các biến tĩnh sẽ không hoạt động chính xác theo cùng một cách.
+26

Chức năng nội tuyến không phải lúc nào cũng đảm bảo được inline: Bởi vì trình biên dịch sẽ không nội tuyến nếu làm như vậy sẽ tạo ra mã chậm hơn. Trình biên dịch thực hiện rất nhiều phân tích rằng Kỹ sư không thể và thực hiện điều đúng. –

+10

Tôi tin rằng các hàm đệ quy là một ví dụ khác mà hầu hết các trình biên dịch bỏ qua nội tuyến. – LBushkin

+0

Có bất kỳ sự khác biệt quan trọng nào trong C so với C++ trong trường hợp này không? – rzetterberg

11

Sự khác biệt chính là kiểm tra loại. Trình biên dịch sẽ kiểm tra xem những gì bạn vượt qua như là giá trị đầu vào là các loại có thể được chuyển vào hàm. Điều đó không đúng với các macro tiền xử lý - chúng được mở rộng trước khi kiểm tra bất kỳ loại nào và có thể gây ra các lỗi nghiêm trọng và khó phát hiện.

Here là một số điểm ít rõ ràng khác được nêu.

1

Một dấu chấm câu nội tuyến hoạt động theo cú pháp giống như hàm bình thường, cung cấp loại an toàn và phạm vi cho các biến địa phương và quyền truy cập vào các thành viên lớp nếu đó là phương thức. Ngoài ra khi gọi các phương thức nội tuyến, bạn phải tuân theo các giới hạn riêng tư/được bảo vệ.

2

Chức năng nội tuyến sẽ duy trì ngữ nghĩa giá trị, trong khi macro tiền xử lý chỉ sao chép cú pháp. Bạn có thể nhận được các lỗi rất tinh tế với macro tiền xử lý nếu bạn sử dụng đối số nhiều lần - ví dụ: nếu đối số chứa đột biến như "i ++" có thực thi hai lần đó là một điều bất ngờ. Một hàm nội tuyến sẽ không có vấn đề này.

8

Macro bỏ qua các không gian tên. Và điều đó khiến họ trở nên xấu xa.

63

Trước tiên, macro tiền xử lý chỉ là "sao chép dán" trong mã trước khi biên dịch.Vì vậy, không có loại kiểm tra, và một số tác dụng phụ có thể xuất hiện

Ví dụ, nếu bạn muốn so sánh 2 giá trị:

#define max(a,b) ((a<b)?b:a) 

Các tác dụng phụ xuất hiện nếu bạn sử dụng max(a++,b++) ví dụ (a hoặc b sẽ được tăng lên hai lần). Thay vào đó, sử dụng (ví dụ)

inline int max(int a, int b) { return ((a<b)?b:a); } 
+0

Chỉ muốn thêm vào ví dụ của bạn ngoài tác dụng phụ, macro cũng có thể đưa thêm tải công việc, xem xét 'max (fibonacci (100), giai thừa (10000))' lớn hơn sẽ được tính hai lần: ( – watashiSHUN

0

Trong GCC (Tôi không chắc chắn về những người khác), định nghĩa một hàm inline, chỉ là một gợi ý để trình biên dịch. Nó vẫn còn lên đến trình biên dịch vào cuối ngày để quyết định có hay không nó bao gồm phần thân của hàm bất cứ khi nào nó được gọi.

Sự khác biệt giữa các chức năng nội tuyến và macro tiền xử lý tương đối lớn. Các macro tiền xử lý chỉ là thay thế văn bản vào cuối ngày. Bạn từ bỏ rất nhiều khả năng cho trình biên dịch thực hiện kiểm tra về kiểm tra kiểu trên các đối số và kiểu trả về. Đánh giá các đối số là khác nhau nhiều (nếu các biểu thức bạn truyền vào các hàm có các hiệu ứng phụ bạn sẽ có một lần gỡ lỗi thời gian rất thú vị). Có những khác biệt nhỏ về chức năng và macro có thể được sử dụng. Ví dụ nếu tôi có:

#define MACRO_FUNC(X) ... 

đâu MACRO_FUNC rõ ràng xác định cơ quan chức năng. chăm sóc đặc biệt cần phải được thực hiện để nó chạy một cách chính xác trong mọi trường hợp một chức năng có thể được sử dụng, ví dụ như một kém bằng văn bản MACRO_FUNC sẽ gây ra lỗi trong

if(MACRO_FUNC(y)) { 
...body 
} 

Một chức năng bình thường có thể được sử dụng với không có vấn đề đó.

9

Để thêm sự khác biệt khác với những điều đã được cung cấp: bạn không thể bước qua một #define trong trình gỡ lỗi, nhưng bạn có thể thực hiện một hàm nội tuyến.

0

Từ góc độ mã hóa, hàm nội tuyến giống như một hàm. Vì vậy, sự khác biệt giữa một hàm nội tuyến và macro là giống như sự khác biệt giữa hàm và macro.

Từ góc độ biên dịch, một hàm nội tuyến tương tự như macro. Nó được tiêm trực tiếp vào mã, không được gọi.

Nói chung, bạn nên xem xét các hàm nội tuyến là các hàm bình thường với một số tối ưu hóa nhỏ được trộn lẫn. Và giống như hầu hết các tối ưu hóa, tùy thuộc vào trình biên dịch để quyết định xem nó có thực sự quan tâm để áp dụng nó hay không. Thông thường trình biên dịch sẽ vui vẻ bỏ qua bất kỳ nỗ lực nào của lập trình viên để nội tuyến một hàm, vì nhiều lý do khác nhau.

3

chức năng nội tuyến tương tự như macro (vì mã chức năng được mở rộng tại thời điểm cuộc gọi tại thời gian biên dịch), các hàm nội tuyến được phân tích bởi trình biên dịch, trong khi macro được mở rộng bởi bộ tiền xử lý. Do đó, có một số khác biệt quan trọng:

  • Chức năng nội tuyến tuân theo tất cả các giao thức về an toàn loại được thực thi trên các chức năng bình thường.
  • Các chức năng nội tuyến được chỉ định sử dụng cú pháp giống như bất kỳ hàm nào khác ngoại trừ việc chúng bao gồm từ khóa nội tuyến trong khai báo hàm.
  • Biểu thức được chuyển làm đối số cho hàm nội tuyến được đánh giá một lần.
  • Trong một số trường hợp, các biểu thức được truyền dưới dạng đối số cho macro có thể được đánh giá nhiều lần. http://msdn.microsoft.com/en-us/library/bf6bf4cf.aspx

  • macro được mở rộng vào thời gian biên dịch trước, bạn không thể sử dụng chúng để gỡ lỗi, nhưng bạn có thể sử dụng các hàm nội dòng.

-- good article: http://www.codeguru.com/forum/showpost.php?p=1093923&postcount=1

;

+0

Cảm ơn bạn câu trả lời của bạn. – Subodh

0

chức năng nội tuyến sẽ hoạt động như một cuộc gọi chức năng nếu có tồn tại bất kỳ câu lệnh lặp lại hoặc đệ quy nào trong đó, để tránh việc thực hiện lặp lại các lệnh. Nó khá hữu ích để tiết kiệm bộ nhớ tổng thể của chương trình của bạn.

12

Các Inline chức năng được mở rộng bởi trình biên dịch nơi như các macro được mở rộng bởi các Preprocessor, đó là chỉ substitution.Hence văn bản

  • Không có kiểm tra kiểu trong invocation vĩ mô trong khi kiểm tra kiểu được thực hiện trong suốt gọi hàm.

  • Kết quả không mong muốn và không hiệu quả có thể xảy ra trong quá trình mở rộng macro do đánh giá lại các đối số và thứ tự hoạt động. Ví dụ

    #define MAX(a,b) ((a)>(b) ? (a) : (b)) 
    int i = 5, j = MAX(i++, 0); 
    

    sẽ cho kết quả trong

    int i = 5, j = ((i++)>(0) ? (i++) : (0)); 
    
  • Những lập luận vĩ mô không được đánh giá trước khi mở rộng vĩ mô

    #define MUL(a, b) a*b 
    int main() 
    { 
        // The macro is expended as 2 + 3 * 3 + 5, not as 5*8 
        printf("%d", MUL(2+3, 3+5)); 
    return 0; 
    } 
    // Output: 16` 
    
  • Các từ khóa trở lại không thể được sử dụng trong các macro để trở về giá trị như trong trường hợp chức năng.

  • chức năng nội tuyến có thể bị quá tải

  • Các thẻ truyền cho macro có thể được nối bằng hành ## được gọi là toán tử Mã-dán.

  • Macro thường được sử dụng để sử dụng lại mã khi các hàm nội tuyến được sử dụng để loại bỏ thời gian trên (thời gian dư thừa) trong khi gọi hàm (tránh nhảy tới chương trình con).

Các vấn đề liên quan