Câu trả lời:
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 hết mọi nơi trong mã của bạn vì chúng được thay thế bằng các bản mở rộng của chúng trước khi bất kỳ quá trình biên dịch nào bắt đầu.
Các hàm nội tuyến là các hàm thực mà phần thân của nó được đưa trực tiếp vào trang web cuộc gọi của chúng. Chúng chỉ có thể được sử dụng khi một lệnh gọi hàm thích hợp.
Bây giờ, khi sử dụng macro so với các hàm nội tuyến trong ngữ cảnh giống như hàm, hãy lưu ý rằng:
Đầu tiên, các macro của bộ xử lý trước chỉ là "sao chép dán" trong mã trước khi biên dịch. Vì vậy, không có kiểm tra loại 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++)
chẳng hạn ( a
hoặc b
sẽ được tăng lên hai lần). Thay vào đó, hãy sử dụng (ví dụ)
inline int max( int a, int b) { return ((a<b)?b:a); }
max(fibonacci(100), factorial(10000))
lớn hơn một sẽ được tính gấp đôi :(
Hàm Inline được mở rộng bởi trình biên dịch khi các macro được mở rộng bởi Bộ tiền xử lý, nó chỉ là sự thay thế văn bản.
Không có kiểm tra kiểu trong khi gọi macro trong khi kiểm tra kiểu được thực hiện trong khi 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 vĩ mô 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ẽ dẫn đến
int i = 5, j = ((i++)>(0) ? (i++) : (0));
Các đối số macro không được đánh giá trước khi mở rộng macro
#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`
Từ khóa return không thể được sử dụng trong macro để trả về giá trị như trong trường hợp của hàm.
Các hàm nội tuyến có thể bị quá tải
Các mã thông báo được chuyển cho macro có thể được nối bằng cách sử dụng toán tử ## được gọi là toán tử Dán mã.
Macro thường được sử dụng để tái sử dụng mã khi các hàm nội tuyến được sử dụng để loại bỏ chi phí thời gian (thời gian dư thừa) trong khi gọi hàm (tránh nhảy đến một chương trình con).
Sự khác biệt chính là kiểm tra kiểu. Trình biên dịch sẽ kiểm tra xem những gì bạn chuyển vào làm giá trị đầu vào có thuộc loại có thể được truyền vào hàm hay không. Điều đó không đúng với macro của bộ xử lý trước - chúng được mở rộng trước khi kiểm tra kiểu bất kỳ và điều đó có thể gây ra lỗi nghiêm trọng và khó phát hiện.
Dưới đây là một số điểm ít rõ ràng hơn được nêu ra.
Để thêm một sự khác biệt khác cho những thứ đã đượ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ể bước qua một hàm nội tuyến.
Macro đang bỏ qua không gian tên. Và điều đó khiến họ trở nên xấu xa.
Các hàm nội tuyến tương tự như macro (vì mã hàm được mở rộng tại điểm gọi tại thời điểm biên dịch), các hàm nội tuyến được trình biên dịch phân tích cú pháp, trong khi macro được mở rộng bởi bộ tiền xử lý. Kết quả là, có một số khác biệt quan trọng:
Trong một số trường hợp, các biểu thức được truyền làm đố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 tại thời điểm trước khi biên dịch, 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 tuyến.
- bài viết hay : http://www.codeguru.com/forum/showpost.php?p=1093923&postcount=1
;
Một hàm nội tuyến sẽ duy trì ngữ nghĩa giá trị, trong khi macro bộ tiền xử lý chỉ sao chép cú pháp. Bạn có thể gặp các lỗi rất nhỏ với macro bộ xử lý trước 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 khá bất ngờ. Một hàm nội tuyến sẽ không có vấn đề này.
Một hàm nội tuyến hoạt động theo cú pháp giống như một hàm thông thường, cung cấp sự an toàn về kiểu và phạm vi cho các biến cục bộ của hàm và quyền truy cập vào các thành viên lớp nếu nó là một 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 thủ các hạn chế riêng tư / được bảo vệ.
Để biết sự khác biệt giữa macro và hàm nội tuyến , trước hết chúng ta nên biết chính xác chúng là gì và khi nào chúng ta nên sử dụng chúng.
CHỨC NĂNG :
int Square(int x){
return(x*X);
}
int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
Các lệnh gọi hàm có chi phí liên quan đến nó, vì sau khi hàm kết thúc thực thi, nó phải biết nơi nó phải trả về và cũng cần lưu giá trị trong bộ nhớ ngăn xếp.
Đối với các ứng dụng nhỏ thì sẽ không có vấn đề gì, nhưng hãy lấy ví dụ về các ứng dụng tài chính mà hàng nghìn giao dịch đang diễn ra mỗi giây, chúng ta không thể thực hiện với các lệnh gọi hàm.
MACROS:
# define Square(x) x*x;
int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
int result = Square (x * x)
Nhưng macro có các lỗi liên quan đến nó.
#define Square(x) x*x
int main() {
int val = 5;
int result = Square(val + 1);
cout << result << endl;
return 0;
}
Ở đây đầu ra là 11 không phải 36 .
CÁC CHỨC NĂNG TRỰC TUYẾN :
inline int Square(int x) {
return x * x;
}
int main() {
using namespace std;
int val = 5;
int result = Square(val + 1);
cout << result << endl;
return 0;
}
Đầu ra 36
Từ khóa nội tuyến 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, ở đây kết quả đầu ra là chính xác vì trước tiên nó đánh giá biểu thức và sau đó được truyền vào. không cần bộ nhớ cho các đối số của hàm.
So sánh giữa Macro và Hàm nội tuyến:
PHẦN KẾT LUẬN:
Các hàm nội tuyến đôi khi hữu ích hơn macro, vì nó cải thiện hiệu suất và an toàn khi sử dụng cũng như giảm chi phí cuộc gọi hàm. Nó chỉ là một yêu cầu đối với trình biên dịch, một số hàm nhất định sẽ không được đưa vào như:
đó là một điều tốt, bởi vì đó là bất cứ khi nào trình biên dịch nghĩ rằng tốt nhất là làm mọi thứ theo cách khác.
Trong GCC (tôi không chắc về những người khác), việc khai báo một hàm nội tuyến, chỉ là một gợi ý cho trình biên dịch. Vào cuối ngày, trình biên dịch vẫn quyết định xem nó có bao gồm phần thân của hàm hay không bất cứ khi nào nó được gọi.
Sự khác biệt giữa các hàm trong dòng và macro tiền xử lý là tương đối lớn. Macro tiền xử lý chỉ là sự thay thế văn bản vào cuối ngày. Bạn mất rất nhiều khả năng để trình biên dịch thực hiện kiểm tra kiểu kiểm tra 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 chuyển vào các hàm có tác dụng phụ, bạn sẽ có một thời gian gỡ lỗi rất thú vị). Có sự khác biệt nhỏ về nơi có thể sử dụng các hàm và macro. Ví dụ nếu tôi có:
#define MACRO_FUNC(X) ...
Trong đó MACRO_FUNC rõ ràng xác định phần thân của hàm. Cần chú ý đặc biệt để nó chạy chính xác trong mọi trường hợp một hàm có thể được sử dụng, ví dụ MACRO_FUNC viết kém 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 mà không có vấn đề gì ở đó.
Từ quan điểm của mã hóa, một hàm nội tuyến giống như một hàm. Do đó, sự khác biệt giữa hàm nội tuyến và macro cũng 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ư một macro. Nó được tiêm trực tiếp vào mã, không được gọi.
Nói chung, bạn nên coi các hàm nội tuyến là các hàm thông thường với một số tối ưu hóa nhỏ xen vào. Và giống như hầu hết các tối ưu hóa, trình biên dịch quyết định xem nó có thực sự muốn áp dụng nó hay không. Thường thì 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 dòng một hàm, vì nhiều lý do khác nhau.
Các hàm nội tuyến sẽ hoạt động như một lời gọi hàm nếu tồn tại bất kỳ câu lệnh lặp hoặc đệ quy nào trong đó, để ngăn việc thực thi lặp lại các lệnh. Nó khá hữu ích để lưu bộ nhớ tổng thể của chương trình của bạn.
#include<iostream>
using namespace std;
#define NUMBER 10 //macros are preprocessed while functions are not.
int number()
{
return 10;
}
/*In macros, no type checking(incompatible operand, etc.) is done and thus use of micros can lead to errors/side-effects in some cases.
However, this is not the case with functions.
Also, macros do not check for compilation error (if any). Consider:- */
#define CUBE(b) b*b*b
int cube(int a)
{
return a*a*a;
}
int main()
{
cout<<NUMBER<<endl<<number()<<endl;
cout<<CUBE(1+3); //Unexpected output 10
cout<<endl<<cube(1+3);// As expected 64
return 0;
}
Macro thường nhanh hơn các hàm vì chúng không liên quan đến chi phí cuộc gọi hàm thực tế.
Một số Nhược điểm của macro: Không có kiểm tra kiểu. Khó gỡ lỗi vì chúng gây ra sự thay thế đơn giản.Macro không có không gian tên, vì vậy macro trong một phần mã có thể ảnh hưởng đến phần khác. Macro có thể gây ra các tác dụng phụ như trong ví dụ CUBE () ở trên.
Macro thường là một lớp lót. Tuy nhiên, chúng có thể bao gồm nhiều hơn một dòng, không có ràng buộc nào như vậy trong các hàm.
#define TWO_N(n) 2 << n
sau đó cout << CUBE(TWO_N(3 + 1)) << endl;
? (Đó là tốt hơn để kết thúc dòng đầu ra với endl
hơn để bắt đầu họ với nó.)