2015-05-23 24 views
7

Chúng ta đều biết làm thế nào để khai báo một cấu trúc trong C:Khai báo cấu trúc: typedef struct name name;

struct Label1{ /* variables */ } Label2; // As I learned 

Nhưng tôi muốn biết tại sao mã này hoạt động mà không tuyên bố 'tên struct':

typedef struct name s_name; 

Hoặc là trong thực tế, không gõ mã số

struct name; 

có nghĩa là tôi đã tuyên bố 'tên cấu trúc' là cấu trúc khoảng trống hoặc một cái gì đó như thế này?

Ví dụ mã:

typedef struct Data Data; 
struct Data{ /*variables*/ }; 

Nếu trong lần đầu tiên dữ liệu dòng struct được khai báo là một khoảng trống một, sau đó trong lần thứ hai nó giống như tôi đang redeclaring nó với các thành viên.

Giải thích cho điểm này là gì?

+2

cấu trúc C được danh nghĩa đánh máy, tức là loại sắc trong một đơn vị dịch được xác định bởi tên; 'struct name' là đủ để khai báo một kiểu mới, nhưng kiểu sẽ không đầy đủ cho đến khi một khai báo hoàn chỉnh khác (aka definition) được gặp; bạn có thể có con trỏ đến các đối tượng với kiểu không đầy đủ, nhưng rõ ràng là sẽ không thể truy cập các thành viên hoặc sử dụng nó để khai báo các biến; tờ khai loại không đầy đủ còn được gọi là tờ khai chuyển tiếp; một trong những ứng dụng của nó là các con trỏ mờ đục – Christoph

+1

@ Michael Heidelberg "Chúng ta đều biết cách khai báo một cấu trúc trong C" - sau câu hỏi của bạn, tôi không chắc rằng nó là đúng. :) –

Trả lời

8

Cái gì như:

struct MyStruct; 

Được gọi là một tài liệu tham khảo về phía trước. Nó tạo ra một loại không đầy đủ và nói với trình biên dịch sẽ có một loại tên đó (và nó là một cấu trúc - nó hoạt động tương tự như vậy cho các công đoàn), và các chi tiết "theo sau". Loại như vậy bạn không thể xác định các biến, cho đến khi bạn hoàn thành loại.

typedef struct MyStruct MyType; 

Chỉ cần xác định tên loại là cấu trúc đó. Đây vẫn là loại không đầy đủ.

Tuy nhiên, bạn có thể mất một con trỏ đến một loại không đầy đủ:

MyType *my_t_pointer; 
struct MyStruct *my_s_pointer; 

này rất hữu ích cho một cấu trúc để có con trỏ tới các đối tượng cùng loại khi bạn cung cấp việc kê khai đầy đủ, "hoàn thành" loại :

struct MyStruct { 
    struct MyStruct *next; 
}; 

Thực ra đây là cách duy nhất để tạo nút cho danh sách, cây và tất cả cấu trúc dữ liệu đệ quy khác. Đây là phần chính của các chương trình C (đôi khi bị ẩn).

Ngoài ra, cơ chế này được sử dụng để ẩn chi tiết triển khai. Các hàm trong tiêu đề chỉ cần biết cấu trúc tồn tại để lấy/truyền con trỏ tới nó. Việc sử dụng các chức năng này không cần phải biết chi tiết của cấu trúc (nhưng theo cách này nó không thể phân bổ nó, vì vậy mô-đun phải bao gồm tất cả các khía cạnh cần biết chi tiết về cấu trúc). Khai báo đầy đủ chỉ nằm bên trong tệp thực hiện của mô-đun. Những con trỏ này được gọi là "mờ đục" như một người không thể "xem qua", tức là truy cập vào các trường của cấu trúc vì chúng đơn giản là không được biết đến.

my_module.h:

struct MyStruct; 

extern void my_init(struct MyStruct *obj); 

my_module.c:

struct MyStruct { 
    int f1; 
    ... 
}; 

my_init(struct MyStruct *obj) 
{ 
    ... 
} 
+0

Tôi hiểu rồi; cảm ơn vì lời giải thích này. –

2

Các typedef tuyên bố s_name như một bí danh cho tên struct để bạn có thể khai báo các biến, ví dụ:

s_name *sptr; 

Dòng

struct name; 

tuyên bố rằng có một cấu trúc kiểu gọi tên mà không xác định Nội dung của nó. Điều này thường được thực hiện để có thể khai báo các biến là con trỏ đối với loại cấu trúc. Bạn không thể khai báo các biến của kiểu cấu trúc thực tế cho đến khi nó được định nghĩa.

+1

Tôi hiểu rằng có hai ký hiệu: khai báo kết cấu ; và xác định nội dung của nó? –

+0

Ususlly được kết hợp nhưng có thể khai báo kiểu cấu trúc mà không xác định nội dung của nó. Đó là một tuyên bố không đầy đủ, xem thêm nhận xét của Christoph. –

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