2011-07-31 25 views
8

Có hai tệp nguồn trong chương trình của tôi.Tuyên bố không nên khớp với định nghĩa của nó khi mảng được tham gia?

Mảng được xác định trong A.cpp.

// compiler: MSVC2005 SP2  
// A.cpp 

// defines an array of type "int [100]" 
int a[100] = {3}; 

Được sử dụng trong B.cpp.

// B.cpp 

// declares an array of type "int []" 
extern int a[]; 

int main() 
{ 
    // prints 3 correctly 
    cout << a[0] << endl; 
    return 0; 
} 

AFAIK, trình liên kết sẽ phát sinh lỗi nếu không tìm thấy định nghĩa phù hợp cho khai báo nếu số nhận dạng được khai báo được sử dụng. Ở đây, int []int [100] là hai loại khác nhau, hiển nhiên.

Tại sao, trong trường hợp này, không có bất kỳ lỗi liên kết nào? Được đảm bảo bởi Chuẩn rằng kích thước mảng là không đáng kể trong khi khớp với khai báo/định nghĩa? Hoặc nó chỉ thực hiện cụ thể? Trích dẫn từ Tiêu chuẩn sẽ được đánh giá cao nếu có.

Edit: iammilind đề cập trong câu trả lời của ông rằng mối liên kết có thể chạy một cách chính xác (trình biên dịch của ông là gcc) ngay cả khi loại không phù hợp giữa tuyên bố và định nghĩa. Nó có được yêu cầu bởi tiêu chuẩn hay chỉ là một cách của gcc? Tôi đoán đây là một vấn đề quan trọng hơn rất nhiều để tìm ra.

+2

Lỗi nằm trong "rõ ràng". –

+0

@Alf. Không. Trích dẫn từ tiêu chuẩn 8.3.4 "Loại " chuỗi khai báo-kiểu-danh sách-loại-danh sách của NT "là một kiểu khác với kiểu" khai báo-khai báo-loại-danh sách mảng không xác định ràng buộc của T, " –

+0

@Erik Thay vì đi vào một cuộc thảo luận về những gì mà "rõ ràng" đòi hỏi, mà tất nhiên bạn biết tốt nhất !, Tôi đề nghị bạn chọn câu trả lời của AndreyT như là giải pháp, mặc dù trong quan điểm của tôi sử dụng từ "trận đấu "là một chút sai lầm.Dù sao, lý do mà bạn có thể nhận được những thứ để liên kết nơi các loại không phù hợp với các quy tắc ngôn ngữ cho phù hợp, là trình biên dịch không đi đến rất nhiều nỗ lực để bắt lỗi ở đây. –

Trả lời

7

Trong cả C và C++, khai báo đối tượng a loại không đầy đủ sẽ khớp với định nghĩa đối tượng a nơi loại hoàn tất. Những gì bạn quan sát chỉ đơn giản minh họa thực tế rằng trong C++ bạn được phép sử dụng các kiểu không đầy đủ trong các khai báo không xác định. Nhưng một khi bạn nhận được để định nghĩa loại phải được hoàn thành.

Hành vi này không bị giới hạn đối với mảng.Ví dụ, bạn có thể khai báo

extern class X x; 

cho một lớp học hoàn toàn chưa biết X, và sau đó, khi class X đã được xác định đầy đủ, bạn có thể xác định

X x; 

mà sẽ phù hợp với tuyên bố trên.

Điều tương tự cũng xảy ra với mảng của bạn. Trước hết bạn khai báo một đối tượng của loại không đầy đủ

extern int a[]; 

và sau đó bạn định nghĩa nó với đầy đủ loại

int a[100]; 

Các loại ở đây thực sự không phù hợp. Tuy nhiên, ngôn ngữ C++ không bao giờ yêu cầu chúng phải khớp. Ví dụ, 3,9/7 khẳng định một cách rõ ràng

Loại tuyên bố của một đối tượng mảng có thể là một mảng không rõ kích thước và do đó không đầy đủ tại một thời điểm trong một đơn vị dịch thuật và hoàn chỉnh sau này; các loại mảng tại hai điểm đó (“mảng của ràng buộc không xác định của T” và “mảng của N T”) là các loại khác nhau.

Điều này có nghĩa là cùng một đối tượng mảng có thể có loại không đầy đủ ban đầu, nhưng có được loại hoàn chỉnh sau này. (Xem thêm ví dụ trong 3.9/7). Điều này không, tất nhiên, có nghĩa là bạn có thể khai báo a làm int và sau đó xác định nó là double. Sự tự do liên quan đến loại duy nhất bạn có ở đây là, một lần nữa, để hoàn thành một loại không đầy đủ. Không còn nữa.

+0

Điều đó có ý nghĩa đối với "loại không đầy đủ". Nhưng tại sao nó vẫn liên kết nếu tôi khai báo "extern int a [50]"? "int [50]" là một kiểu hoàn chỉnh, khác biệt (so với int [100]). –

+0

@Eric, Bây giờ, đó là vì mangling, lý tưởng này không nên biên dịch, nhưng trình biên dịch của bạn không bao gồm kích thước trong tên bị xé. – unkulunkulu

+0

@unkulunkulu, ok, vậy Standard có yêu cầu khai báo phải khớp với định nghĩa nếu cả hai đều là loại hoàn chỉnh? –

0

Ở đây nó nói rằng "C++ cho phép khả năng để trống các dấu ngoặc vuông []. Trong trường hợp này, trình biên dịch sẽ giả định kích thước cho mảng khớp với số lượng giá trị được bao gồm giữa dấu ngoặc {}". Vì vậy, nếu ref này là đúng, nó có vẻ là một phần của tiêu chuẩn.

http://www.cplusplus.com/doc/tutorial/arrays/

+0

@Laurent, ý của bạn là định nghĩa mảng int [] = {3} và những gì tôi yêu cầu là khai báo không xác định extern int a []; –

0

Câu hỏi của bạn là chính hãng. Ở đây có vài vấn đề.

Khi bạn khai báo hai biểu tượng có cùng tên; sau đó không có kiểm tra từ linker cho loại/kích thước của nó vv Nó chỉ giải quyết chúng và tương quan chúng lại với nhau. Ví dụ: thử khai báo extern float a[]; hoặc extern int a[3]; nó sẽ vẫn hoạt động. Đây là cách C++ linker là (không may) được thiết kế.

Vì vậy, giải pháp là khai báo chúng trong tệp tiêu đề và #include trong cả hai tệp a.cpp và b.cpp.

+0

Bạn có chắc chắn khai báo một biến kiểu-nhưng-cùng-tên khác có thể chuyển liên kết không? Đó không phải là trường hợp, ít nhất là trong MSVC. –

+0

@Eric: tôi đã thử 'extern int * a'' extern double * a', 'extern char * a' và tương tự như những gì @Marcelo Cantos đã đề cập, tôi cũng đã thử' extern int (* a) (int, char *) ', tất cả đều thông qua liên kết. Nhưng không phải trong MSVC. Tôi đang sử dụng gcc-4.5. Nhưng vâng tôi đã xóa câu lệnh 'cout'. –

+0

@Eric, Trong gcc nó trôi qua; trình liên kết phù hợp với 2 biến độc lập có cùng tên trong các đơn vị dịch khác nhau. Vì vậy, nó tốt hơn để 'extern' nó trong một tập tin tiêu đề và' # include' nó trong bất cứ điều gì '.cpp'. – iammilind

1

Trước hết mã đó không được cung cấp bất kỳ lỗi nào. Các đặc điểm kỹ thuật int a[] là khác nhau từ a[100] nhưng tương thích với nó (nó chỉ là không đầy đủ).

Điểm quan trọng thứ hai là bạn không thể đếm trên trình biên dịch/trình liên kết C++ đưa ra lỗi cho sự thiếu kết nối mô-đun chéo. Ví dụ trong một chương trình C++ bạn không thể có cùng một lớp được định nghĩa hai lần với một định nghĩa khác, nhưng trình biên dịch không được yêu cầu cho bạn biết về vấn đề này, đó là một gánh nặng còn lại trên các lập trình viên.

Nếu triển khai phát hiện và báo hiệu loại vấn đề này thì tốt, nhưng triển khai không nói bất kỳ điều gì về chúng và chỉ tạo tệp thi hành bị lỗi vẫn hoàn toàn tuân thủ.

0

này liên kết sau đây:

http://www.lysator.liu.se/c/c-faq/c-2.html

có lời giải thích bạn đang tìm kiếm.

+0

Liên kết phải có trong nhận xét chứ không phải câu trả lời. Câu trả lời phải chứa một số ngữ cảnh. – unkulunkulu

+0

chắc chắn ... nhưng nếu liên kết chứa câu trả lời chính xác thì sao? –

+0

Hãy xem http://stackoverflow.com/questions/how-to-answer :) Tôi đề nghị bạn trích dẫn một số phần của nội dung được liên kết. – unkulunkulu

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