2016-09-29 15 views
18

Theo tiêu chuẩn C:Bên ngoài, nội bộ và không có liên kết hoặc lý do tại sao điều này không hoạt động?

In the set of translation units and libraries that constitutes an entire program, each declaration of a particular identifier with external linkage denotes the same object or function. Within one translation unit, each declaration of an identifier with internal linkage denotes the same object or function. Each declaration of an identifier with no linkage denotes a unique entity.

Trong ví dụ của tôi, chúng tôi có ba tờ khai riêng biệt với mỗi dạng có một linkage.So khác nhau tại sao không làm việc này?

static int a; //a_Internal 

int main(void) { 
    int a; //a_Local 
    { 
     extern int a; //a_External 
    } 
    return 0; 
} 

Lỗi:

In function 'main': Line 9: error: variable previously declared 'static' redeclared 'extern'

Tại sao biên dịch nhấn mạnh rằng tôi redeclaring thay vì cố gắng truy cập vào đối tượng bên ngoài trong tập tin khác?

hợp lệ C++ ví dụ để tham khảo:

static void f(); 
static int i = 0;    // #1 
void g() { 
    extern void f();    // internal linkage 
    int i;      // #2 i has no linkage 
    { 
    extern void f();   // internal linkage 
    extern int i;    // #3 external linkage 
    } 
} 

Cả Clang và VC dường như sẽ ổn với ví dụ C của tôi; chỉ một số phiên bản của GCC (không phải tất cả) sản xuất lỗi nói trên.

+0

Vì vậy, bạn đã đọc đoạn 2, tốt, bây giờ hãy thử đọc đoạn 6, sau đó đoạn 4, ngay cả sau đó, nếu bạn có câu hỏi, vui lòng quay lại . :) –

+2

Với gcc bạn nhận được lỗi này, nhưng không phải với tiếng kêu. –

+1

(Thực tế thú vị: Trong C++ đề cập đến mã này (như hợp lệ!) Trong ví dụ trong [basic.link]/6.) –

Trả lời

16

§6.2.2, 7 nói:

If, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined.

Vì vậy, chương trình của bạn có undefined behaviour.

§6.2.2, 4 nói rằng

extern int a; //a_External 

có mối liên hệ bên ngoài vì việc khai báo trước khi có thể nhìn thấy trong phạm vi int a; //a_Localkhông liên kết. Nhưng

static int a; //a_Internal 

khai báo a với liên kết nội bộ.Do đó, đó là undefined cho mỗi §6.2.2, 7.

+0

Có vẻ như tôi đã không nghĩ về ngoại lệ này. Bất kỳ lý do nào cho tuyên bố này? – user6898756

+2

@ user6898756 Lý do: Ngăn cấm các kết quả không thể hiểu được về các quy tắc kỳ bí và bí truyền mà không có lợi ích rõ ràng? Chỉ có thể thôi? Plus, có lẽ, một cơ hội tốt hơn để xây dựng trình biên dịch và trình liên kết chính xác. –

2

Trình biên dịch được đưa ra lỗi này vì bên trong phạm vi a_External, a_Internal vẫn còn dễ tiếp cận, do đó bạn đang redeclaring a_Internalstatic-extern trong a_External vì sự va chạm tên của a. Vấn đề này có thể được giải quyết bằng cách sử dụng tên biến khác nhau, ví dụ:

static int a1; //a_Internal 

int main(void) { 
    int a2; //a_Local 
    { 
     extern int a3; //a_External 
    } 
    return 0; 
} 
+0

Sử dụng giải thích của bạn, a_Local cũng không hoạt động. – user6898756

+0

FYI: Nếu số nhận dạng chỉ định hai thực thể khác nhau có cùng tên không gian, phạm vi có thể trùng lặp. Nếu vậy, phạm vi của một pháp nhân ( phạm vi bên trong ) sẽ kết thúc nghiêm ngặt trước phạm vi của pháp nhân kia (số phạm vi bên ngoài ). Trong phạm vi bên trong, mã định danh chỉ định thực thể được khai báo trong phạm vi bên trong; ** đối tượng được khai báo trong phạm vi bên ngoài là ẩn (và không hiển thị) trong phạm vi bên trong **. – user6898756

+0

@ user6898756 đó không phải là cách nó hoạt động, xem báo giá trong câu hỏi: tất cả các khai báo của định danh với liên kết biểu thị cùng một thực thể (chúng không ẩn bất kỳ khai báo nào khác có liên kết) –

1

C tiêu chuẩn nói:

In the set of translation units each declaration of a particular identifier with external linkage denotes the same entity (object or function). Within one translation unit, each declaration of an identifier with internal linkage denotes the same entity.

Trong bộ của các đơn vị dịch chúng ta không thể có nhiều thực thể bên ngoài khác nhau có cùng tên, do đó, các loại của mỗi khai báo biểu thị rằng thực thể bên ngoài duy nhất phải đồng ý. Chúng tôi có thể kiểm tra xem các loại có đồng ý trong một đơn vị dịch thuật hay không, điều này được thực hiện tại thời điểm biên dịch. Chúng tôi không thể kiểm tra xem các loại có đồng ý giữa các đơn vị dịch thuật khác nhau ở thời điểm biên dịch hay không tại thời gian liên kết.

For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible,31) if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration. If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage.

static int a; //a_Internal 

int main(void) { 
    int a; //No linkage 
    { 
     extern int a; //a_External 
    } 
    return 0; 
} 

đây tuyên bố trước đó của tên là a không có mối liên hệ, vì vậy extern int a có mối liên hệ bên ngoài. Nó có nghĩa là chúng ta phải định nghĩa int trong một đơn vị dịch thuật khác. Tuy nhiên, GCC đã quyết định từ chối mã này với lỗi đã được khai báo trước đây static bị lỗi redeclared 'extern', có thể do chúng tôi có hành vi không xác định theo tiêu chuẩn C.

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