2015-06-09 24 views
12

Trong khi trả lời warning: assignment from incompatible pointer type for linklist array, tôi nhận thấy bất kỳ số nhận dạng không khai báo nào bị lỗi với struct từ khóa được coi là số nhận dạng được khai báo chuyển tiếp.Tất cả các mã định danh cấu trúc được tự động chuyển tiếp khai báo

Ví dụ các program below biên dịch tốt:

/* Compile with "gcc -std=c99 -W -Wall -O2 -pedantic %" */ 
#include <stdio.h> 

struct foo 
{ 
    struct bar *next; /* Linked list */ 
}; 


int main(void) { 
    struct bar *a = 0; 
    struct baz *b = 0; 
    struct foo c = {0}; 

    printf("bar -> %p\n", (void *)a); 
    printf("baz -> %p\n", (void *)b); 
    printf("foo -> %p, %zu\n", (void *)&c, sizeof c); /* Remove %zu if compiling with -ansi flag */ 
    return 0; 
} 

Câu hỏi của tôi: Những quy tắc hướng dẫn một trình biên dịch C để điều trị chưa được khai báo struct identifier s như mong tuyên bố không đầy đủ struct loại?

+0

Tôi không biết nhưng có lẽ vì trong khi ở giữa tuyên bố 'struct anything' bạn cần để có thể sử dụng 'struct anything', và có thể trình biên dịch sẽ không xử lý tất cả điều đó và chỉ cần đối xử với nó như hiện ? – Eregrith

Trả lời

10

Tiêu chuẩn nói (6.2.5.28)

Tất cả các con trỏ đến cấu trúc loại sẽ có các yêu cầu đại diện và liên kết tương tự như nhau.

này có nghĩa là trình biên dịch biết làm thế nào để đại diện cho các con trỏ tới bất kỳ cấu trúc, ngay cả những người được (chưa) không xác định.
Chương trình của bạn chỉ giao dịch với con trỏ đến các cấu trúc như vậy, vì vậy nó ổn.

+0

Điều này nghe có vẻ hợp lý. Điều này không làm cho việc khai báo trở nên vô dụng. –

+0

Trong trường hợp cụ thể của việc sử dụng con trỏ đến cấu trúc, có. Khai báo một cấu trúc không đầy đủ trước khi sử dụng một con trỏ đến nó là không cần thiết. – pmg

+1

Nhưng tạo phương thức 'typedef' đến một loại không đầy đủ có thể hữu ích trong việc cho phép loại trình biên dịch kiểm tra các đối số danh sách mà theo dõi sử dụng typedef như trái ngược với chỉ đơn giản là đi qua con trỏ void. Câu trả lời tốt. –

7

Nó được mô tả trong 6.2.5 Loại và 6.7.2.3 Thẻ.

struct identifier là loại đối tượng.

6.2.5 Các loại

  1. Ý nghĩa của một giá trị được lưu trữ trong một đối tượng hoặc trả về bởi một hàm được xác định bởi các loại của biểu thức dùng để truy cập nó. (Một định danh được khai báo là đối tượng là biểu thức đơn giản nhất, loại được chỉ định trong khai báo của mã định danh.) Các loại được phân chia thành các loại đối tượng (loại mô tả đối tượng) và loại chức năng (loại mô tả chức năng) . Tại các điểm khác nhau trong một đơn vị dịch, một loại đối tượng có thể là không đầy đủ (thiếu thông tin đầy đủ để xác định kích thước của các đối tượng thuộc loại đó) hoặc hoàn chỉnh (có đủ thông tin). 37)

37) Một loại có thể không đầy đủ hoặc hoàn toàn một đơn vị dịch toàn bộ, hoặc nó có thể thay đổi trạng thái ở điểm khác nhau trong một đơn vị dịch thuật.

  1. Loại mảng có kích thước không xác định là loại không đầy đủ. Nó được hoàn thành, cho một định danh của loại đó, bằng cách xác định kích thước trong một tuyên bố sau này (với liên kết nội bộ hoặc bên ngoài). Một cấu trúc hoặc loại liên kết không rõ nội dung (như được mô tả trong 6.7.2.3) là một loại không đầy đủ. Nó được hoàn thành, cho tất cả các khai báo kiểu đó, bằng cách khai báo cùng một cấu trúc hoặc thẻ liên kết với nội dung xác định của nó sau này trong cùng một phạm vi.

6.7.2.3 Thẻ

  1. Tất cả các tờ khai của cơ cấu, công đoàn, hoặc các loại được liệt kê có phạm vi tương tự và sử dụng cùng một thẻ khai báo cùng một loại. Không phân biệt liệu có một thẻ hay những gì khác là các tờ khai khác thuộc cùng một đơn vị dịch, loại không đầy đủ 129) cho đến ngay sau cú đúp đóng của danh sách xác định nội dung và hoàn thành sau đó.

129) Loại không đầy đủ chỉ có thể được sử dụng khi kích thước của đối tượng thuộc loại đó là không cần thiết. Nó không phải là cần thiết, ví dụ, khi một tên typedef được khai báo là một specifier cho một cấu trúc hoặc union, hoặc khi một con trỏ tới hoặc một hàm trả về một cấu trúc hoặc union được khai báo. (Xem các loại không đầy đủ trong 6.2.5.) Đặc điểm kỹ thuật phải được hoàn thành trước khi hàm được gọi hoặc được xác định.

6

Ngoài câu trả lời được cung cấp bởi 2501 và nhận xét của bạn về "Trong trường hợp của tôi, thậm chí không có tờ khai chuyển tiếp", như sau.

Bất kỳ sử dụng mã số struct tag nào được tính là (chuyển tiếp) khai báo kiểu cấu trúc, nếu nó chưa được khai báo trước đó. Mặc dù một cách chính thức hơn có thể nói rằng điều này đơn giản được tính là một loại, vì tiêu chuẩn C không đề cập đến "các khai báo chuyển tiếp của các loại cấu trúc", chỉ cần hoàn thành và incomplete structure types (6.2.5p22).

6.7.2 Type specifiers cho chúng ta biết một struct-hoặc-đoàn-specifier là một type-specifier, và 6.7.2.1 Structure and union specifiers paragraph 1 cho chúng ta biết rằng lần lượt structđịnh danh là một struct-hoặc-đoàn -specifier.

Giả sử bạn có một tuyên bố danh sách liên kết, một cái gì đó giống như

struct node { 
    struct node *next; 
    int element; 
}; 

sau đó là "tuyên bố mong ngầm" của loại không đầy đủ này là điều cần thiết cho cấu trúc này để làm việc. Sau cùng, loại struct nodeis only complete tại dấu chấm phẩy chấm dứt. Nhưng bạn cần phải tham khảo nó để khai báo con trỏ next.

Ngoài ra, tuyên bố struct node (loại không đầy đủ) có thể nằm ngoài phạm vi, giống như bất kỳ tuyên bố nào khác. Điều này xảy ra ví dụ nếu bạn có một số nguyên mẫu

int function(struct unknown *parameter); 

nơi struct unknown đi ra khỏi phạm vi ngay ở phần cuối của việc kê khai. Bất kỳ khai báo tiếp theo nào thì struct unknown s thì không giống như cái này.Điều đó được hàm ý trong văn bản của 6.2.5p22:

Cấu trúc hoặc loại liên kết không rõ nội dung (như được mô tả trong 6.7.2.3) là loại không đầy đủ. Nó được hoàn thành, cho tất cả các tờ khai đó loại, bằng cách tuyên bố cấu trúc tương tự hoặc thẻ công đoàn với nó xác định nội dung sau trong cùng một phạm vi.

Đó là lý do tại sao gcc cảnh báo về vấn đề này:

foo.c:1:21: warning: 'struct unknown' declared inside parameter list 
foo.c:1:21: warning: its scope is only this definition or declaration, which is probably not what you want 

Bạn có thể khắc phục điều này bằng cách đặt một tờ khai chuyển tiếp thêm trước đó, mà làm cho phạm vi bắt đầu sớm hơn (và do đó kết thúc sau):

struct unknown; 
int function(struct unknown *parameter); 
2

Tôi nghĩ rằng trường hợp sử dụng trang nhã nhất khi sử dụng các loại cấu trúc không hoàn chỉnh như sau:

struct foo 
{ 
    struct bar *left; 
    struct bar *right; 
}; 
struct bar 
{ 
    int something; 
    struct foo *next; 
}; 

I.e. đệ quy kép, trong đó một điểm đến điểm b và điểm b đến a. Các trường hợp như vậy có thể là lý do tại sao tính năng này được bao gồm trong đặc tả ngôn ngữ gốc của C.

Câu hỏi ban đầu là liệu tất cả các định danh cấu trúc có được tự động chuyển tiếp tuyên bố hay không. Tôi nghĩ rằng sẽ tốt hơn nếu nói rằng tất cả các định nghĩa cấu trúc chưa hoàn chỉnh được tự động xem là khai báo chuyển tiếp.

Edit: Tiếp theo nhận xét về tài liệu, chúng ta hãy nhìn vào kinh thánh ngôn ngữ C: Kerninghan & Ritchie - C Programming Language, phần "6.5 Cấu trúc tự tham chiếu" nói:

Thỉnh thoảng, một cần một biến thể của cấu trúc tự tham chiếu: hai cấu trúc liên quan đến nhau. Cách xử lý này là:

struct t { 
    ... 
    struct s *p; /* p points to an s */ 
}; 
struct s { 
    ... 
    struct t *q; /* q points to a t */ 
}; 

Tôi đồng ý, rằng chúng ta có thể thực hiện một cách khác, nhưng tôi sẽ có động lực tốt này từ tác giả của ngôn ngữ C và tôi đồng ý với họ rằng đó là cách thanh lịch để thực hiện điều này.

+0

Cảm ơn câu trả lời. Bạn có thể đạt được các chức năng rất tốt với một tuyên bố về phía trước của 'struct bar' ở trên' struct foo', do đó, điều này không thể được tính là động lực thực sự.Ngoài động lực để tự động chuyển tiếp tuyên bố, tôi đang tìm nơi mà nó được ghi lại trong thông số kỹ thuật. –

+0

@MohitJain: Vui lòng xem bản chỉnh sửa của tôi cho nơi nó được ghi lại. – ludvik02

+0

Cảm ơn. Tôi có thể thấy điều này trên P115 trong phiên bản của tôi, mặc dù các tác giả đã chọn không xây dựng điều này, nhưng vâng, nó xuất hiện nội dung có chủ ý và không có chi tiết nào bị bỏ qua. –

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