2011-10-28 23 views
5

Vì một lý do nào đó, tôi nhận được nhiều khai báo nội dung trong tệp tiêu đề của mình mặc dù tôi đang sử dụng bộ phận bảo vệ tiêu đề. mã ví dụ của tôi là dưới đây:Tiêu đề/Bao gồm nhân viên bảo vệ không hoạt động?

main.c:

#include "thing.h" 

int main(){ 
    printf("%d", increment()); 

    return 0; 
} 

thing.c:

#include "thing.h" 

int increment(){ 
    return something++; 
} 

thing.h:

#ifndef THING_H_ 
#define THING_H_ 

#include <stdio.h> 

int something = 0; 

int increment(); 

#endif 

Khi tôi cố gắng để biên dịch này, GCC nói rằng tôi có nhiều định nghĩa về biến số. ifndef nên chắc chắn rằng điều này không xảy ra, vì vậy tôi nhầm lẫn vì sao nó lại xảy ra.

+2

Lỗi * trình biên dịch * "nhiều * khai báo *" không giống với * linker * error "multiple * definitions *". Bạn đã đề cập đến cả hai trong câu hỏi của bạn (trong khi thực tế vấn đề duy nhất là sau này); hiểu sự khác biệt là chìa khóa để hiểu những gì đang xảy ra. Các tiêu đề bảo vệ ngăn chặn nhiều * khai báo *, không nhiều * định nghĩa *. – Clifford

+0

@Clifford xin lỗi, tôi cần phải đề cập đến tôi đã nhận được một lỗi liên kết. – user1007968

+0

Ngoài ra, trong C 'int increment();' không phải là một mẫu thử nghiệm nhưng khai báo một hàm với số lượng tham số không xác định. Sử dụng 'int increment (void);' cho điều đó. –

Trả lời

9

Bộ bảo vệ bao gồm hoạt động chính xác và không phải là nguồn gốc của sự cố.

Điều gì xảy ra là mọi đơn vị biên dịch bao gồm thing.h đều có số int something = 0 riêng, vì vậy trình liên kết phàn nàn về nhiều định nghĩa.

Đây là cách bạn khắc phục điều này:

thing.c:

#include "thing.h" 

int something = 0; 

int increment(){ 
    return something++; 
} 

thing.h:

#ifndef THING_H_ 
#define THING_H_ 

#include <stdio.h> 

extern int something; 

int increment(); 

#endif 

Bằng cách này, chỉ thing.c sẽ có một thể hiện của something, và main.c sẽ đề cập đến nó.

+2

Bạn cũng có thể thêm rằng ngay cả khi không có nhiều lỗi định nghĩa, mỗi TU sẽ có bản sao riêng của biến và nó sẽ không đạt được mục đích chia sẻ cùng một biến trên tất cả các tệp nguồn. –

3

Bạn có một định nghĩa trong mỗi đơn vị dịch (một trong số main.c và một trong số thing.c). Các tiêu đề bảo vệ ngăn chặn tiêu đề được bao gồm nhiều lần trong một đơn vị dịch đơn lẻ .

Bạn cần phải tuyên bốsomething trong file header, và chỉ xác định nó trong thing.c, giống như chức năng:

thing.c:

#include "thing.h" 

int something = 0; 

int increment(void) 
{ 
    return something++; 
} 

thing.h:

#ifndef THING_H_ 
#define THING_H_ 

#include <stdio.h> 

extern int something; 

int increment(void); 

#endif 
4

Vệ sĩ tiêu đề sẽ dừng tệp khỏi compi dẫn nhiều hơn một lần trong cùng một đơn vị biên dịch (tệp). Bạn đang bao gồm nó trong main.c và thing.c, do đó, nó sẽ được biên dịch một lần trong mỗi, dẫn đến biến something được khai báo một lần trong mỗi đơn vị, hoặc hai lần trong tổng số.

1

Biến số something phải được xác định trong tệp .c, chứ không phải trong tệp tiêu đề.

Chỉ cấu trúc, macro và khai báo loại cho các biến và các nguyên mẫu chức năng phải nằm trong tệp tiêu đề. Trong ví dụ của bạn, bạn có thể khai báo loại somethingextern int something trong tệp tiêu đề.Nhưng định nghĩa của biến phải nằm trong tệp .c.

Với những gì bạn đã làm, biến something sẽ được xác định trong mỗi file.c bao gồm thing.h và bạn nhận được một thông báo lỗi "một cái gì đó được xác định nhiều lần" khi GCC cố gắng liên kết tất cả mọi thứ lại với nhau.

+0

Câu lệnh đầu tiên của bạn không đúng. Biến phải được * khai báo * với * extern * từ khóa trong tệp tiêu đề và * được định nghĩa * trong một tệp nguồn duy nhất. –

1

cố gắng tránh xác định các biến trên toàn cầu. sử dụng các hàm như increment() để sửa đổi và đọc giá trị của nó thay thế. theo cách đó bạn có thể giữ biến tĩnh trong tệp thing.c và bạn biết chắc chắn rằng chỉ các hàm từ tệp đó sẽ sửa đổi giá trị.

+0

Ah, vì vậy đây là cách bạn tránh các biến toàn cục trong C. Cảm ơn bạn đã cung cấp thông tin. – user1007968

0

những gì ifndef được bảo vệ là .h được bao gồm trong một .c nhiều lần. Ví dụ:

điều. h

#ifndef 
#define 

int something = 0; 
#endif 

thing2.h

#include "thing.h" 

main.c

#include "thing.h" 
#include "thing2.h" 
int main() 
{ 
    printf("%d", something); 
    return 0; 
} 

nếu tôi rời khỏi ifndef ra sau đó GCC sẽ phàn nàn

In file included from thing2.h:1:0, 
      from main.c:2: 
thing.h:3:5: error: redefinition of ‘something’ 
thing.h:3:5: note: previous definition of ‘something’ was here 
+0

Trong khi giải thích của bạn là chính xác, vấn đề của OP không phải là, bảo vệ bao gồm chắc chắn * tại chỗ *. –

+0

@ Xin lỗi, OP? – manuzhang

+0

OP = Áp phích gốc –

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