2008-10-30 30 views
32

Tôi có một tệp tiêu đề x.h được bao gồm bởi nhiều tệp * .c nguồn. Tệp tiêu đề này có một số biến cấu trúc được xác định.Tại sao những người bảo vệ biên dịch của tôi không ngăn cản nhiều sự bao gồm định nghĩa?

Tôi đã đưa nhiều vệ phòng bao gồm ở phần đầu của tập tin tiêu đề như:

#ifndef X_H 
#define X_H 
... 
.. 
//header file declarations and definitons. 


#endif//X_H 

On tòa nhà tôi nhận được lỗi mối liên kết liên quan đến nhiều định nghĩa. Tôi hiểu vấn đề.

  1. sẽ không phải là một bao gồm bảo vệ ngăn ngừa nhiều ở phía trên cùng của tập tin tiêu đề như tôi đã, ngăn chặn nhiều thể vùi của tập tin tiêu đề x.h và do đó tránh nhiều định nghĩa của các biến mà đang có trong x.h?

  2. #pragma một khi không hoạt động trên trình biên dịch cụ thể này, vậy giải pháp là gì? Ai đó đã đăng this câu trả lời cho một câu hỏi tương tự. Nó dường như không hiệu quả với tôi. Giải pháp này hoạt động như thế nào?

+1

@Stephen: Nếu bạn đã chỉnh sửa tiêu đề câu hỏi, vui lòng xem phần thân (và có thể là thẻ, mặc dù không có ở đây). Điều này tránh chỉnh sửa trùng lặp (và chạm). –

+0

@Paulo Thiếu nó, tôi đã cố gắng để xem cho nó mặc dù, nhờ lời nhắc nhở! – Stephen

Trả lời

2

Sử dụng một người bảo vệ nhiều bao gồm ngăn biên dịch lỗi, nhưng bạn đang nhận được một lỗi mối liên kết. Bạn có định nghĩa dữ liệu trong tệp tiêu đề không sử dụng extern không?

9

Sử dụng bộ bao gồm bảo vệ ngăn một đơn vị biên dịch bao gồm tiêu đề hai lần. Ví dụ. nếu tiêu đề B.h bao gồm A.h và B.cpp bao gồm A.h và B.h, mọi thứ từ A.h sẽ được khai báo hai lần trong biên soạn B.cpp nếu bạn không sử dụng bao gồm cả bảo vệ.

Nhân viên bảo vệ của bạn ngăn điều này xảy ra, tất cả đều ổn cho đến bây giờ. Nhưng bạn nhận được nhiều định nghĩa tại thời gian liên kết, tức là hai đơn vị biên dịch xác định cùng một điều, điều này có nghĩa là bạn có định nghĩa thực trong tiêu đề của mình, sử dụng extern cho tất cả các biến, đảm bảo chức năng nội tuyến hoặc được xác định trong tệp cpp.

35

Nếu trình liên kết đang khiếu nại, điều đó có nghĩa là bạn có định nghĩa chứ không phải chỉ là khai báo trong tiêu đề của bạn. Đây là một ví dụ về những điều sẽ sai.

#ifndef X_H 
#define X_H 

int myFunc() 
{ 
    return 42; // Wrong! definition in header. 
} 

int myVar; // Wrong! definition in header. 

#endif 

Bạn nên chia này vào nguồn và tập tin tiêu đề như thế này:

Tiêu đề:

#ifndef X_H 
#define X_H 

extern int myFunc(); 

extern int myVar; 

#endif 

C Nguồn:

int myFunc() 
{ 
    return 42; 
} 

int myVar; 
+0

'int myVar;' tối đa là định nghĩa dự kiến; nó thường không gây rắc rối. Nếu có một khởi tạo, nó sẽ. Tuy nhiên, tôi luôn luôn sử dụng một extern rõ ràng khi bạn hiển thị trong phiên bản 'cố định'. –

+0

@ Jonathan: Có một thứ như "định nghĩa dự kiến" trong tiêu chuẩn C không ?? Tôi nghĩ điều xảy ra là nhiều định nghĩa như thế này gây ra "hành vi không xác định", nhưng trong nhiều trình biên dịch/liên kết (gcc ...), hành vi bạn nhận được thực sự là những gì bạn muốn! – Roddy

+0

nó sẽ có thể có một tuyên bố nội tuyến của một chức năng theo ngay lập tức bởi định nghĩa của nó? –

4

Nếu các chức năng không phải là lớn, bạn có thể sử dụng "inline" trước chúng và linker sẽ không phàn nàn.

7

Vệ sĩ tiêu đề chỉ tốt cho một đơn vị biên dịch đơn lẻ, tức là, tệp nguồn. Nếu bạn tình cờ bao gồm một tệp tiêu đề nhiều lần, có lẽ vì tất cả tiêu đề được bao gồm từ main.c lần lượt bao gồm stdio.h thì các nhân viên bảo vệ sẽ trợ giúp.

Nếu bạn có định nghĩa của một hàm f trong x.h được bao gồm bởi main.cutil.c, sau đó nó cũng giống như sao chép và dán các định nghĩa của f vào main.c khi tạo main.o và làm tương tự cho util.c để tạo util.o. Sau đó, mối liên kết sẽ khiếu nại và điều này xảy ra mặc dù bảo vệ tiêu đề của bạn. Bạn có thể có nhiều câu lệnh #include "x.h" trong số main.c do các vệ sĩ này.

+0

Tôi đã có nghi ngờ này từ lâu! Giải thích của bạn xóa nó :-) – Shailesh

0

Có thể X_H đã được xác định ở một nơi khác? Tôi chỉ gặp vấn đề này, trong đó Xlib định nghĩa X_H trong /usr/include/X11/X.h.

Để kiểm tra, bạn có thể gọi gcc -dM -E (nếu bạn đang sử dụng gcc), ví dụ: trong hệ thống xây dựng mà tôi đang sử dụng làm việc với CC=gcc CFLAGS="-dM -E" make. Nếu tệp đầu ra chứa #define X_H mặc dù bạn xóa nó khỏi tệp của mình (ví dụ: sử dụng Y_H), thì tệp đó đã được xác định bên ngoài mã nguồn của bạn.

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