2013-07-01 26 views
9

Tôi đã chạy các mã sau đây được biên soạn với nhau như: gcc A.c B.c -o combinedextern trong nhiều file và có thể định nghĩa đôi

Chương trình A:

#include<stdio.h> 
int a=1; 
int b; 
int main() 
{ 
extern int a,b; 
fun(); 
printf("%d %d\n",a,b); 
} 

Chương trình B:

int a; 
int b=2; 
int fun() 
{ 
printf("%d %d\n",a,b); 
return 0; 
} 

On chạy " kết hợp "chương trình đầu ra là:

1 2 
1 2 
.210

Bây giờ, tôi đã một vài nghi ngờ về điều này một:

  1. Tại sao không phải là kết quả:

  2. Are không phải là một và b được định nghĩa hai lần?

Vui lòng giải thích rõ ràng, tôi đã gặp rất nhiều vấn đề khi hiểu rõ hơn và đôi khi những nghi ngờ này thường xuyên xảy ra.

Cảm ơn trước.

+1

bạn cố gắng lừa trình biên dịch và trình biên dịch đã lừa bạn. –

+5

Nó không phải về việc đánh lừa trình biên dịch, Đó là về việc nhận các khái niệm đúng. – tapananand

Trả lời

3

Vì vậy, tôi trả lời câu hỏi của riêng mình sau một thời gian dài. Mặc dù tuyên bố:

int b; là một decalaration và int b = 2; là định nghĩa

là đúng nhưng lý do mọi người đều cho là không rõ ràng.

Đã không có int b = 2;, int b; là định nghĩa, vì vậy sự khác biệt là gì?

Sự khác biệt nằm trong cách trình liên kết xử lý nhiều định nghĩa biểu tượng. Có một khái niệm về các biểu tượng yếu và mạnh.

Bộ lắp ráp mã hóa thông tin này ngầm trong bảng biểu tượng của tệp đối tượng có thể định vị lại. Các hàm và các biến toàn cục được khởi tạo nhận các ký hiệu mạnh. Các biến toàn cục chưa được khởi tạo nhận các ký hiệu yếu.

Vì vậy, trong Program A, int a = 1 là một biểu tượng mạnh mẽ trong khi int b; là một biểu tượng yếu, tương tự như trong Program B, int b = 2 là một biểu tượng mạnh mẽ và trong khi int a là yếu.

Với khái niệm này những biểu tượng mạnh mẽ và yếu đuối, linkers Unix sử dụng các quy tắc sau để đối phó với các biểu tượng được xác định nhiều:

  1. Nhiều hiệu mạnh không được phép.
  2. Với biểu tượng mạnh và nhiều biểu tượng yếu, hãy chọn biểu tượng mạnh.
  3. Cho nhiều biểu tượng yếu, chọn bất kỳ ký hiệu yếu nào.

Vì vậy, bây giờ chúng ta có thể tranh luận về những gì đang xảy ra trong trường hợp trên.

  1. Trong int b = 2int b, trước đây là một biểu tượng mạnh mẽ trong khi sau này là yếu nên b được định nghĩa với giá trị 2.
  2. Trong int a = 1int a, một được định nghĩa là 1 (cùng lập luận).

Do đó, đầu ra 1 2.

1

Theo như tôi biết: Đầu ra sẽ là 1 2 và 1 2 vì bạn định nghĩa a và b dưới dạng biến bên ngoài trong hàm chính. Do đó, nó cũng sẽ cố gắng lấy giá trị từ các tệp khác. Theo như câu hỏi thứ 2 tôi nghĩ rằng trình biên dịch đang lấy giá trị khởi tạo của biến và hợp nhất chúng bởi vì cả a và b được định nghĩa là biến toàn cục trong cả hai tệp. Trường hợp có thể khác nếu cả hai được xác định bên trong hàm. Bất kỳ đề xuất hoặc đầu vào nào khác đều được chào đón.

3

Bởi vì các biến không được xác định hai lần tại đây; họ được tuyên bố hai lần mặc dù. Các hàm lấy các giá trị từ định nghĩa của các biến không phải từ việc khai báo các biến.

Tuyên bố giới thiệu mã định danh và mô tả loại khai báo. Thông báo qua chúng tôi đảm bảo với người khiếu nại rằng biến hoặc hàm này đã được xác định ở nơi khác trong chương trình và sẽ được cung cấp tại thời điểm liên kết. Như ví dụ khai báo là:

extern int a;

Một định nghĩa thực sự instantiates/thực hiện định danh này. Định nghĩa là: int a=5; HOẶC int a;

Chỉ cần đọc on this link để tham khảo thêm.

there is this wonderful đăng trên ngăn xếp quá tải.

extern nói với trình biên dịch mà biến được định nghĩa bên ngoài như vậy có vẻ ngoài chức năng và có nó tìm thấy:

int a=1 trong chương trình A và int b=2 trong chương trình B

Đối với các biến AUTO:

int a;//both definition and declaration

Để biết thêm về STORAGE CLASSES, bạn có thể follow this link

int a bên ngoài chính hoặc bất kỳ chức năng nào khác là khai báo (tức là GLOBAL) chỉ bên trong bất kỳ hàm nào được gọi là định nghĩa của nó.

+0

Theo như tôi biết int a; là cả khai báo và định nghĩa và bên ngoài bất kỳ hàm nào, nó cũng trở thành khởi tạo với giá trị 0. Hãy xem xét: int main() { int a; // cả khai báo và định nghĩa ... int a = 5; // đưa ra nhiều định nghĩa lỗi của a. } Bạn cũng có thể thử tương tự cho các biến bên ngoài. – tapananand

+0

Ya, tôi biết sự khác biệt, nhưng những gì tôi đang nói là viết int a; cả hai tuyên bố cũng như định nghĩa tức là cấp phát bộ nhớ cho a. Bên ngoài bất kỳ chức năng nào nó cũng khởi tạo nó với một giá trị được xác định rõ (0) và không phải là một giá trị rác. – tapananand

+0

Xin lỗi vì đã có vấn đề về quyền lực trễ .... Những gì bạn đang nói có thể đúng với các biến Auto nhưng không phải là biến ngoài, chỉ cần nhìn vào liên kết trong câu trả lời của tôi. – 0decimal0

5

Biến có thể được khai báo nhiều lần, miễn là các khai báo nhất quán với nhau và với định nghĩa. Nó có thể được khai báo trong nhiều mô-đun, bao gồm mô-đun nơi nó được xác định và thậm chí nhiều lần trong cùng một mô-đun.

Biến bên ngoài cũng có thể được khai báo bên trong một hàm. Trong trường hợp này, từ khóa extern phải được sử dụng, nếu không trình biên dịch sẽ xem nó là định nghĩa của biến cục bộ, có một phạm vi, tuổi thọ và giá trị ban đầu khác. Khai báo này sẽ chỉ hiển thị bên trong hàm thay vì xuyên suốt mô-đun của hàm.

Bây giờ hãy để tôi lặp lại một lần nữa định nghĩa của extern mà nói "biến bên ngoài là một biến ĐỊNH NGHĨA bên ngoài bất kỳ khối chức năng" (Xin đọc kỹ lời được đưa ra trong BOLD). Vì vậy, cho Programe Aa có nét nhưng b chỉ là lời tuyên bố rất extern sẽ tìm kiếm định nghĩa của 'b' được đưa ra trong Programe B Vì vậy, in từ Programe A1 2 Now cho phép Talk về Programe B có tuyên bố cho a và định nghĩa cho b vì vậy giá trị này là giá trị của a từ programe A và giá trị của b từ tệp hiện tại.

+0

Theo như tôi biết int a; là cả khai báo và định nghĩa và bên ngoài bất kỳ hàm nào, nó cũng trở thành khởi tạo với giá trị 0. Hãy xem xét: int main() { int a; // cả khai báo và định nghĩa ... int a = 5; // đưa ra nhiều định nghĩa lỗi của a. } Bạn cũng có thể thử tương tự cho các biến bên ngoài. – tapananand

+1

@TapanAnand mặc định khởi tạo xảy ra khi định nghĩa không có sẵn. Nhưng trong trường hợp của bạn 'a' và' b' đều được khai báo và xác định đúng để trình biên dịch sẽ không khởi tạo lại chúng và tất cả điều này là để tránh nhiều lỗi định nghĩa. –

+0

Ok, do đó, int b; trong Prog A có thể không phải là khởi tạo, nhưng nó phải được định nghĩa, vậy tại sao int b = 2 trong prog B không gây ra lỗi? – tapananand

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