2010-08-24 37 views
8

Như tiêu đề nói; sự khác biệt trong thực tế giữa từ khóa nội tuyến và chỉ thị tiền xử lý #define là gì?Sự khác biệt trong thực tế giữa nội dòng và #define là gì?

+0

thể trùng lặp của [chức năng Inline vs Preprocessor macro] (http (Vâng, tôi thừa nhận rằng làm điều này với abs là một chút nhân tạo, nhưng tôi hy vọng bạn sẽ có được hình ảnh.): // stackoverflow.com/questions/1137575/inline-functions-vs-preprocessor-macros) – jww

Trả lời

37

#define là công cụ tiền xử lý và có ngữ nghĩa vĩ mô. Xem xét việc này, nếu max(a,b) là một macro được định nghĩa là

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

Ex 1:

val = max(100, GetBloodSample(BS_LDL)) sẽ tràn thêm máu vô tội, bởi vì chức năng sẽ thực sự được gọi là hai lần. Điều này có thể có nghĩa là sự khác biệt hiệu suất đáng kể đối với các ứng dụng thực.

Ex 2:

val = max(3, schroedingerCat.GetNumPaws()) này cho thấy một sự khác biệt nghiêm trọng trong chương trình logic, bởi vì đây không ngờ có thể trở lại một số trong đó là ít hơn 3 - một cái gì đó người dùng sẽ không mong đợi.

Ex 3:

val = max(x, y++) có thể tăng y nhiều hơn một lần.


Với chức năng nội tuyến, không có trường hợp nào trong số này xảy ra.

Lý do chính là khái niệm macro nhắm vào tính minh bạch của việc triển khai (thay thế mã văn bản) và nội dung các khái niệm ngôn ngữ thích hợp, làm cho ngữ nghĩa yêu cầu minh bạch hơn cho người dùng.

+3

+1 Đối với ví dụ tràn máu – Tomas

+2

Bạn nên thay đổi 'shroedingerCat.GetNumPaws()' thành một hàm C chứ không phải C++. – alternative

+0

Vâng, câu hỏi là về C; nó là mặc dù phổ biến hơn cho các hàm thành viên C++ để trả về những thứ khác nhau theo thời gian, bởi vì chúng tự nhiên dựa vào trạng thái của đối tượng của chúng. –

1

Macros (tạo ra với #define) luôn thay thế như bằng văn bản, và có thể có vấn đề đúp đánh giá.

inline mặt khác, hoàn toàn là tư vấn - trình biên dịch tự do bỏ qua nó. Theo tiêu chuẩn C99, một hàm inline cũng có thể có liên kết bên ngoài, tạo ra một định nghĩa hàm có thể được liên kết ngược lại.

1

Vâng, nhiều dòng #define khó viết và chỉnh sửa hơn hàm nội tuyến. Bạn có thể định nghĩa một hàm inline giống như bất kỳ hàm bình thường nào và có thể định nghĩa các biến mà không có vấn đề gì. Hãy tưởng tượng rằng bạn muốn gọi một khối mã nhiều lần trong một hàm khác, và khối mã đó cần các biến riêng của nó: nó dễ dàng hơn với các hàm nội tuyến (có, bạn có thể làm như vậy với #defines và do { ... } while (0); nhưng đó là thứ bạn phải nghĩ về). Ngoài ra, với gỡ lỗi đã bật, bạn thường nhận được khung mô phỏng "được mô phỏng" cho các chức năng nội tuyến có thể làm cho việc gỡ lỗi dễ dàng hơn (ít nhất đó là những gì bạn nhận được khi biên dịch/liên kết với g232's -g và gỡ lỗi với GDB, IIRC). Bạn có thể đặt các điểm ngắt bên trong hàm inline'd của bạn.

Ngoài ra, kết quả gần như giống hệt nhau, AFAIK.

0

Macro giống như chức năng cung cấp cho bạn kiểm tra hoàn toàn bằng không tại nơi chúng được xác định.Khi bạn sử dụng macro, nó sẽ hoạt động tốt ở một nơi và bị hỏng ở một nơi khác và bạn sẽ không biết tại sao cho đến khi bạn mất vài giờ làm việc/thời gian ngủ. Các macro giống như chức năng không hoạt động trên dữ liệu, chúng hoạt động trên mã nguồn. Đôi khi điều này là tốt, ví dụ khi bạn muốn các câu lệnh gỡ lỗi có thể sử dụng lại sử dụng FILELINE nội trang, nhưng phần lớn thời gian, nó có thể được thực hiện tốt với hàm nội tuyến, được kiểm tra cú pháp tại điểm định nghĩa giống như bất kỳ chức năng nào khác.

2

Chức năng (cho dù inline hay không) và macro thực hiện các mục đích khác nhau. Sự khác biệt của họ không nên được coi là hệ tư tưởng như một số dường như mang nó, và những gì là quan trọng hơn, họ có thể làm việc độc đáo với nhau.

Macro là thay thế văn bản được thực hiện tại thời gian biên dịch và họ có thể làm những việc như

#define P99_ISSIGNED(T) ((T)-1 < (T)0) 

mang đến cho bạn một biểu thời gian biên dịch hay không một loại không thể thiếu được ký kết hay không. Đó là, chúng được sử dụng lý tưởng khi loại biểu thức không được biết (ở định nghĩa) và bạn muốn làm điều gì đó về nó. Mặt khác, sự đổ vỡ với các macro là các đối số của chúng có thể được đánh giá nhiều lần, điều này là xấu vì các tác dụng phụ.

Chức năng (inline) Mặt khác được nhập, điều này làm cho chúng trở nên nghiêm ngặt hơn hoặc bị lệch âm, ít linh hoạt hơn. Hãy xem xét các chức năng

inline uintmax_t absU(uintmax_t a) { return a; } 
inline uintmax_t absS(uintmax_t a) { 
    return (-a < a) ? -a : a; 
} 

Đầu tiên thực hiện các tầm thường abs chức năng cho một loại không thể thiếu unsigned. Thứ hai thực hiện nó cho một loại đã ký. (có, phải mất một đối số chưa ký, mục đích này là dành cho mục đích.)

Chúng tôi có thể sử dụng chúng với bất kỳ loại tích phân nào. Tuy nhiên, kiểu trả về sẽ luôn có chiều rộng lớn nhất và có một khó khăn nhất định khi biết cách chọn giữa hai loại.

Bây giờ với vĩ mô

#define ABS(T, A) ((T)(P99_ISSIGNED(T) ? absS : absU)(A)) 

chúng tôi đã thực hiện một gia đình

  • sau các chức năng
  • mà làm việc cho bất kỳ loại không thể thiếu
  • rằng đánh giá đối số của nó chỉ một lần
  • mà bất kỳ trình biên dịch nào gần đây và phong nha sẽ tạo mã tối ưu

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