2013-04-26 24 views
24

tôi xác định chức năng của tôi trong .c (mà không khai báo tiêu đề) như ở đây:C99 chức năng inline trong file .c

inline int func(int i) { 
return i+1; 
} 

Sau đó, trong cùng một tập tin dưới đây tôi sử dụng nó:

... 
i = func(i); 

Và trong quá trình liên kết tôi nhận được "tham chiếu không xác định đối với 'func'". Tại sao?

+2

Hoặc làm cho nó 'tĩnh' hoặc cung cấp định nghĩa không nội tuyến mà trình liên kết có thể tìm thấy. –

+0

Xem thêm http://stackoverflow.com/questions/6312597 – Jens

Trả lời

32

Các inline mô hình trong C99 là một chút khác biệt so với hầu hết mọi người nghĩ, và đặc biệt khác với sử dụng bởi C++

inline chỉ là một gợi ý như vậy mà các trình biên dịch không phàn nàn về những biểu tượng gấp đôi xác định. Nó không đảm bảo rằng một hàm được inlined, cũng không thực sự là một biểu tượng được tạo ra, nếu nó là cần thiết. Để buộc các thế hệ của một biểu tượng bạn muốn có thêm một loại instantiation sau các inline định nghĩa:

int func(int i); 

Thông thường, bạn sẽ phải định nghĩa inline trong một tập tin tiêu đề, mà sau đó được đưa vào một vài .c tệp (đơn vị biên dịch). Và bạn chỉ có dòng trên trong chính xác một trong các đơn vị biên dịch. Bạn có thể chỉ thấy vấn đề mà bạn có bởi vì bạn không sử dụng tối ưu hóa để chạy trình biên dịch của bạn.

Vì vậy, trường hợp sử dụng của bạn có số inline trong tệp .c không có ý nghĩa gì nhiều, tốt hơn chỉ sử dụng static cho điều đó, thậm chí thêm inline không mua cho bạn nhiều.

+0

tuyên bố phạm vi tệp 'extern' của tôi không có' inline' * làm * buộc định nghĩa không phải là nội tuyến – Christoph

+2

Tôi có một câu hỏi, tại sao tình huống này xảy ra khi tối ưu hóa bị tắt?Khi tôi bật nó lên với tùy chọn gcc -O1 nó sẽ chỉ biên dịch, tùy chọn nào trong tối ưu hóa gcc cung cấp mã này được biên dịch theo cách thích hợp? – Lazureus

+1

@Lazureus, khi bạn biên dịch với '-O0', tôi cho rằng bạn có nghĩa là, gcc thường không inline bất kỳ hàm nào. Vì vậy, sau đó bạn * phải * có các biểu tượng được định nghĩa ở đâu đó, nếu không nó sẽ không tìm thấy bất kỳ hàm nội tuyến 'khai báo' nào được định nghĩa. –

21

Ngữ nghĩa nội tuyến C99 thường bị hiểu lầm. Trình chỉ định inline phục vụ hai mục đích:

Đầu tiên, làm gợi ý trình biên dịch trong trường hợp khai báo static inlineextern inline. Ngữ nghĩa vẫn không thay đổi nếu bạn loại bỏ các specifier.

Thứ hai, trong trường hợp nguyên inline (nghĩa là không có static hoặc extern) để cung cấp định nghĩa nội tuyến thay thế cho định dạng bên ngoài, phải có mặt trong một đơn vị dịch khác. Không cung cấp một hành vi bên ngoài là hành vi không xác định, mà thường sẽ biểu hiện như liên kết thất bại.

Điều này đặc biệt hữu ích nếu bạn muốn đặt hàm vào thư viện được chia sẻ, nhưng cũng làm cho nội dung chức năng có sẵn để tối ưu hóa (ví dụ như nội tuyến hoặc chuyên môn hóa). Giả sử một trình biên dịch đủ thông minh, điều này cho phép bạn khôi phục nhiều lợi ích của các mẫu C++ mà không cần phải nhảy qua các vòng tiền xử lý trước.

Lưu ý rằng có một chút lộn xộn hơn tôi đã mô tả ở đây vì có khai báo ngoài nội tuyến phạm vi tệp khác sẽ kích hoạt trường hợp đầu tiên như được mô tả trong câu trả lời của Jens, ngay cả khi định nghĩa đó là inline thay vì extern inline. Điều này là do thiết kế, do đó bạn có thể có một định nghĩa nội tuyến đơn trong một tệp tiêu đề, mà bạn có thể đưa vào tệp nguồn cung cấp tệp bên ngoài bằng cách thêm một dòng cho khai báo bên ngoài.

+0

câu trả lời này có phần lỗi thời - tôi nghĩ có một sai lầm trong Jens, nhưng hóa ra tôi đã nhầm ... – Christoph

+3

Thực ra, giải thích khi nào thì hữu ích ngữ nghĩa là một câu trả lời có giá trị (ít nhất là với tôi). – Vorac