2013-03-24 20 views
6

CLàm cách nào để tham chiếu đến công việc khi có hai tệp .c với các biến toàn cục có cùng biểu tượng nhưng các loại khác nhau?

Nói rằng tôi có các module C sau:

PHẦN 1

#include <stdio.h> 
int x; 
int main(){ 
    foo(); 
    printf("%i\n",x); 
    return 0; 
} 

PHẦN 2

double x; 
void foo(){ 
    x = 3.14; 
} 

Câu hỏi của tôi là: những gì hiện các mối liên kết làm trong này trường hợp? Trong sách giáo khoa tôi đang đọc nó nói trình biên dịch chỉ chọn một trong hai biến toàn cục yếu cho bảng biểu tượng liên kết. Lựa chọn nào trong số này được chọn? Hay cả hai đều được chọn? Nếu vậy, tại sao? Cảm ơn.

Trả lời

5

C cho biết đó là hành vi không xác định.

(C99, 6.9p5) "Nếu số nhận dạng được khai báo với liên kết bên ngoài được sử dụng trong biểu thức (không phải là một phần của toán hạng sizeof mà kết quả là hằng số nguyên), ở đâu đó trong toàn bộ chương trình sẽ có chính xác một định nghĩa bên ngoài cho số nhận dạng, nếu không, sẽ không có nhiều hơn một "

Là hành vi không xác định có nghĩa là trình liên kết có thể hủy bỏ quy trình liên kết trong sự hiện diện của nhiều định nghĩa đối tượng bên ngoài.

Liên kết bây giờ đẹp (hoặc ác, bạn có thể chọn) và thường có tiện ích mở rộng mặc định để xử lý nhiều định nghĩa đối tượng bên ngoài và không bị lỗi trong một số trường hợp.

Nếu bạn đang sử dụng gccld từ binutils, bạn sẽ gặp lỗi nếu hai đối tượng của bạn được khởi tạo rõ ràng. Ví dụ: bạn có int x = 0; trong đơn vị dịch đầu tiên và double x = 0.0;.

Nếu không, nếu một trong các đối tượng bên ngoài không được khởi tạo rõ ràng (tình huống trong ví dụ của bạn) gcc sẽ âm thầm kết hợp hai đối tượng thành một biểu tượng. Bạn vẫn có thể yêu cầu người liên kết báo cáo cảnh báo bằng cách chuyển cho nó tùy chọn --warn-common.

Ví dụ khi liên kết các module:

gcc -Wl,--warn-common module1.o module2.o

Để quá trình liên kết hủy bỏ, bạn có thể yêu cầu các mối liên kết để điều trị tất cả các cảnh báo là lỗi sử dụng --fatal-warnings tùy chọn (-Wl,--fatal-warnings,--warn-common).

Một cách khác để hủy quá trình liên kết là sử dụng tùy chọn trình biên dịch -fno-common, như được giải thích bởi @teppic trong câu trả lời của anh ấy. -fno-common cấm các đối tượng bên ngoài nhận loại biểu tượng chung khi biên dịch. Nếu bạn làm điều đó cho cả hai mô-đun và sau đó liên kết, bạn cũng sẽ nhận được lỗi liên kết nhiều định nghĩa.

gcc -Wall -fno-common -c module1.c module2.c

gcc module1.o module2.o

+0

Vì vậy, trong trường hợp này chỉ có một 'x' trong bảng biểu tượng? Tôi có thể thấy một số lỗi lạ phát sinh từ đó. Thx – amorimluc

+0

@amorimluc trong trường hợp của bạn cơ hội bạn sẽ thích nhận được một lỗi từ linker hoặc một đối tượng duy nhất trong nhị phân cuối cùng và chương trình của bạn sẽ gọi hành vi không xác định. – ouah

+0

Tôi nghĩ rằng tôi sẽ, nhưng nó biên dịch và liên kết tốt. Và x được in dưới dạng int nhưng với mẫu bit của float 3.14. Điều này có thể không xảy ra nhiều trong cuộc sống thực, nhưng chắc chắn sẽ khó tìm ra lỗi tinh vi này trong một chương trình lớn ... – amorimluc

1

Nếu việc thực hiện hỗ trợ nhiều định nghĩa bên ngoài, bạn sẽ kết thúc với một đối tượng đó là một cách hiệu quả đúc với từng loại trong mỗi module, như trong một số loại biến hiệp ngầm. Số lượng bộ nhớ cho loại lớn hơn sẽ được cấp phát và cả hai sẽ hoạt động như các khai báo bên ngoài.

Nếu bạn biên dịch bằng clang hoặc gcc, hãy sử dụng tùy chọn -fno-common để gây ra lỗi cho việc này.

Dưới đây là phần hướng dẫn từ gcc:

 In C code, controls the placement of uninitialized global 
     variables. Unix C compilers have traditionally permitted multiple 
     definitions of such variables in different compilation units by 
     placing the variables in a common block. This is the behavior 
     specified by -fcommon, and is the default for GCC on most targets. 
     On the other hand, this behavior is not required by ISO C, and on 
     some targets may carry a speed or code size penalty on variable 
     references. The -fno-common option specifies that the compiler 
     should place uninitialized global variables in the data section of 
     the object file, rather than generating them as common blocks. 
     This has the effect that if the same variable is declared (without 
     "extern") in two different compilations, you will get a multiple- 
     definition error when you link them. 

Tùy chọn này có hiệu quả thực thi nghiêm ngặt theo tiêu chuẩn ISO C tuân thủ đối với nhiều định nghĩa với.

Hành vi này thường được chấp nhận cho các biến bên ngoài của cùng loại. Theo hướng dẫn của GCC, hầu hết các trình biên dịch hỗ trợ điều này, và (cung cấp các kiểu giống nhau), chuẩn C99 định nghĩa việc sử dụng nó như một phần mở rộng.

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