Bạn cần phân biệt giữa hai khái niệm riêng biệt: định nghĩa hàm và khai báo ký hiệu. "extern" là một công cụ sửa đổi liên kết, một gợi ý cho trình biên dịch về nơi biểu tượng được đề cập sau đó được xác định (gợi ý là "không phải ở đây").
Nếu tôi viết
extern int i;
trong phạm vi tệp (bên ngoài khối chức năng) trong tệp C, khi đó bạn đang nói "biến có thể được xác định ở nơi khác".
extern int f() {return 0;}
vừa là khai báo của hàm f vừa là định nghĩa của hàm f. Các định nghĩa trong trường hợp này vượt qua bên ngoài.
extern int f();
int f() {return 0;}
đầu tiên là một tuyên bố, tiếp theo là định nghĩa.
Sử dụng extern
là sai nếu bạn muốn khai báo và xác định đồng thời một biến phạm vi tệp. Ví dụ,
extern int i = 4;
sẽ đưa ra một lỗi hoặc cảnh báo, tùy thuộc vào trình biên dịch.
Cách sử dụng extern
là hữu ích nếu bạn rõ ràng muốn tránh định nghĩa của một biến.
Hãy để tôi giải thích:
Giả sử tập tin ac chứa:
#include "a.h"
int i = 2;
int f() { i++; return i;}
Các tập tin ah bao gồm:
extern int i;
int f(void);
và tập tin bc chứa:
#include <stdio.h>
#include "a.h"
int main(void){
printf("%d\n", f());
return 0;
}
Extern trong tiêu đề là hữu ích, bởi vì nó nói với trình biên dịch trong giai đoạn liên kết, "đây là một khai báo, và không phải là một định nghĩa". Nếu tôi loại bỏ dòng trong ac xác định i, phân bổ không gian cho nó và gán giá trị cho nó, chương trình sẽ không biên dịch được với tham chiếu không xác định. Điều này cho nhà phát triển biết rằng anh ta đã đề cập đến một biến, nhưng chưa xác định nó. Mặt khác, nếu tôi bỏ qua từ khóa "extern" và xóaint i = 2
dòng, chương trình vẫn biên dịch - tôi sẽ được xác định với giá trị mặc định là 0.
Các biến phạm vi tệp được định nghĩa ngầm định với giá trị mặc định là 0 hoặc NULL nếu bạn không gán rõ ràng một giá trị cho chúng - không giống như các biến phạm vi khối mà bạn khai báo ở đầu hàm. Từ khóa extern tránh định nghĩa ngầm này, và do đó giúp tránh sai lầm.
Đối với các hàm, trong khai báo hàm, từ khóa thực sự là dư thừa. Khai báo hàm không có định nghĩa ngầm.