2013-07-18 43 views
20

Như tiêu đề nói, tôi có mã này:C: typedef struct name {...}; VS typedef struct {...} tên;

typedef struct Book{ 
    int id; 
    char title[256]; 
    char summary[2048]; 
    int numberOfAuthors; 
    struct Author *authors; 
}; 


typedef struct Author{ 
    char firstName[56]; 
    char lastName[56]; 
}; 


typedef struct Books{ 
    struct Book *arr; 
    int numberOfBooks; 
}; 

tôi nhận được các lỗi này từ gcc:

bookstore.c:8:2: error: unknown type name ‘Author’ 
bookstore.c:9:1: warning: useless storage class specifier in empty declaration [enabled by default] 
bookstore.c:15:1: warning: useless storage class specifier in empty declaration [enabled by default] 
bookstore.c:21:2: error: unknown type name ‘Book’ 
bookstore.c:23:1: warning: useless storage class specifier in empty declaration [enabled by default] 

Nếu tôi thay đổi typedefs như thế này:

typedef struct{ 
    char firstName[56]; 
    char lastName[56]; 
} Author; 

Sau đó, không có cảnh báo và không có lỗi nào xảy ra. Có tìm kiếm thông qua http://www.amazon.com/C-Programming-Language-2nd-Edition/dp/0131103628 và một vài giờ googling tôi không thể hình tại sao việc thực hiện đầu tiên sẽ không hoạt động.

+7

di chuyển 'Tác giả' trước 'Sách'. Cũng lưu ý rằng 'typedef' của bạn là dư thừa – SomeWittyUsername

+0

Làm thế nào có thể thay đổi cấu trúc 'Author' đang loại bỏ' error: tên kiểu không xác định 'Book'' cũng vậy? Xin vui lòng có một cái nhìn [ở đây] (http://msdn.microsoft.com/en-us/library/4x7sfztk%28v=vs.80%29.aspx) mà rõ ràng đề cập đến sự khác biệt giữa typdef một cấu trúc và chỉ xác định một cấu trúc. –

Trả lời

46

Có một số điều đang diễn ra tại đây. Thứ nhất, như những người khác đã nói, khiếu nại của trình biên dịch về loại không xác định có thể là do bạn cần xác định các loại trước khi sử dụng chúng. Quan trọng hơn mặc dù là hiểu cú pháp của 3 điều: (1) struct definition, (2) struct declaration, và (3) typedef.

Khi xác định cấu trúc, cấu trúc có thể được đặt tên hoặc chưa đặt tên (nếu chưa đặt tên, thì phải được sử dụng ngay lập tức (sẽ giải thích ý nghĩa của điều này bên dưới)).

struct Name { 
    ... 
}; 

này định nghĩa một loại gọi là "struct Name" mà sau đó có thể được sử dụng để Khai báo một biến struct:

struct Name myNameStruct; 

này khai báo một biến gọi là myNameStruct mà là một struct loại struct Name.

Bạn cũng có thể Xác định một cấu trúc, và khai báo một biến struct cùng một lúc:

struct Name { 
    ... 
} myNameStruct; 

Như trước đây, điều này khai báo một biến gọi là myNameStruct mà là một struct loại struct Name ... Nhưng nó hiện nó cùng lúc khai báo loạistruct Name.
Loại có thể được sử dụng một lần nữa tuyên bố một biến khác:

struct Name myOtherNameStruct; 

Bây giờ typedef chỉ là một cách để bí danh một kiểu với một tên cụ thể:

typedef OldTypeName NewTypeName; 

Với typedef trên, bất cứ lúc nào bạn sử dụng NewTypeName cũng giống như sử dụng OldTypeName. Trong ngôn ngữ lập trình C, điều này đặc biệt hữu ích với cấu trúc, vì nó cho bạn khả năng loại bỏ từ "struct" khi khai báo các biến kiểu đó và để xử lý tên cấu trúc đơn giản như một kiểu riêng của nó (như chúng ta làm trong C++). Dưới đây là một ví dụ mà đầu tiên Xác định cấu trúc, và sau đó Typedefs struct:

struct Name { 
    ... 
}; 

typedef struct Name Name_t; 

Ở phía trên OldTypeName là struct Name và NewTypeName là Name_t. Vì vậy, bây giờ, để khai báo một biến kiểu Tên struct, thay vì viết:

struct Name myNameStruct; 

tôi có thể đơn giản viết:

Name_t myNameStruct; 

LƯU Ý CŨNG, typedef có thể kết hợp với các định nghĩa struct, và đây là những gì bạn đang làm trong mã của bạn:

typedef struct { 
    ... 
} Name_t; 

này cũng có thể được thực hiện trong khi đặt tên cho các cấu trúc, nhưng điều này là không cần thiết:

typedef struct Name { 
    ... 
} Name_t; 

LƯU Ý CŨNG: Trong cú pháp trên, kể từ khi bạn đã bắt đầu với "typedef", sau đó toàn bộ tuyên bố là một tuyên bố typedef, trong đó OldTypeName sẽ xảy ra là một định nghĩa struct. Do đó trình biên dịch diễn giải tên đến sau dấu ngoặc nhọn bên phải} làm NewTypeName ... nó là NOT tên biến (vì nó sẽ nằm trong cú pháp không có typedef, trong trường hợp này bạn sẽ xác định cấu trúc và khai báo một biến struct cùng một lúc).

Hơn nữa, nếu bạn nêu typedef, nhưng để lại ngoài khơi Name_t tại Bấy giờ sự cuối, sau đó bạn đã có hiệu quả tạo ra một tuyên bố typedef INCOMPLETE, bởi vì trình biên dịch xem xét tất cả mọi thứ trong phạm vi "struct Name { ... }" như OldTypeName, và bạn không cung cấp một NewTypeName cho typedef. Đây là lý do tại sao trình biên dịch không hài lòng với mã như bạn đã viết nó (mặc dù các thông điệp của trình biên dịch khá khó hiểu vì nó không hoàn toàn chắc chắn những gì bạn đã làm sai).

Bây giờ, như tôi đã nói ở trên, nếu bạn không đặt tên cho loại struct tại thời điểm bạn định nghĩa nó, sau đó bạn phải sử dụng nó ngay lập tức hoặc để khai báo một biến:

struct { 
    ... 
} myNameStruct; // declares myNameStruct as a variable with this struct 
       // definition, but the definition cannot be re-used. 

Hoặc bạn có thể sử dụng một giấu tên kiểu struct trong một typedef:

typedef struct { 
    ... 
} Name_t; 

cú pháp cuối cùng này là những gì bạn thực sự đã làm khi bạn đã viết:

typedef struct{ 
    char firstName[56]; 
    char lastName[56]; 
} Author; 

Và trình biên dịch đã được hạnh phúc. HTH.

Về những nhận xét/câu hỏi về các hậu tố _T:

_T hậu tố là một quy ước, để chỉ cho người đọc mã mà tên mang tính biểu tượng với _T là một tên Loại (như trái ngược với một tên biến) . Trình biên dịch không phân tích cú pháp, cũng không nhận thức được, của _t.

C89 và đặc biệt là C99, thư viện chuẩn được xác định nhiều loại VÀ CHỌN SỬ DỤNG _t cho tên của các loại đó. Ví dụ C89 tiêu chuẩn định nghĩa wchar_t, off_t, ptrdiff_t. C99 tiêu chuẩn xác định rất nhiều loại bổ sung, chẳng hạn như uintptr_t, intmax_t, int8_t, uint_least16_t, uint_fast32_t, v.v. Nhưng _t không được dành riêng, cũng không được phân tích cú pháp, cũng không nhận thấy bởi trình biên dịch, nó chỉ là một quy ước tốt khi bạn định nghĩa các kiểu mới (thông qua typedef) trong C. Trong C++, nhiều người sử dụng quy ước để bắt đầu nhập tên bằng chữ hoa, ví dụ MyNewType (trái với quy ước C my_new_type_t). HTH

+0

chúng ta có thể khai báo bất kỳ loại nào với hậu tố '_t' không? Tôi nghĩ hậu tố này là C99. Liệu tôi có sai? – nowox

+2

Câu trả lời hay, cảm ơn bạn! – awalllllll

+1

Điều quan trọng cần lưu ý là các cấu trúc tự tham chiếu yêu cầu tên cho cấu trúc hoặc kiểu chữ được khai báo chuyển tiếp. Tôi thích ví dụ nếu tôi muốn một nút LinkedList đã gõ để viết: 'typedef struct node_t {void * data; struct node_t tiếp theo; } Node; 'để khai báo hoàn chỉnh và súc tích. – AaronCarson

0

Bạn chỉ cần xác định Tác giả trước khi xác định Sách.

Bạn sử dụng Tác giả trong sách để nó cần phải được xác định trước đó.

+0

Cảm ơn bạn đã phản hồi nhanh. Không có lỗi xác định Sách trước Tác giả, đã kiểm tra nó trong cuốn sách của Kernighan và Ritchie. –

+0

Tôi đã sai, dường như nó loại bỏ các lỗi nếu tôi thay đổi vị trí. Tôi phải học thêm một chút. (Xin lỗi cho bình luận kép, bộ đếm thời gian đầu tiên trong stackoverflow: P) –

5

Cú pháp là của typedef là như sau:

typedef old_type new_type 

Trong lần thử đầu tiên của bạn, bạn định nghĩa kiểu struct BookkhôngBook. Nói cách khác, kiểu dữ liệu của bạn được gọi là struct Book và không phải là Book.

Trong biểu mẫu thứ hai, bạn đã sử dụng cú pháp đúng là typedef, do đó trình biên dịch nhận ra loại được gọi là Book.

0

Tôi nghĩ là sẽ giúp bạn hiểu. http://www.tutorialspoint.com/cprogramming/c_typedef.htm

bookstore.c:8:2: error: unknown type name ‘Author’ 
bookstore.c:21:2: error: unknown type name ‘Book’ 

Những được sản xuất bởi vì bạn phải xác định chúng trước khi bạn sử dụng chúng. Di chuyển cấu trúc "Tác giả" & "Sách" phía trên cấu trúc "Sách". Điều này sẽ giải quyết nó. Ngoài ra các cảnh báo bạn đang nhận được giải thích lý do tại sao có một vấn đề, trình biên dịch xác định "typedef struct Tác giả" là không cần thiết vì bạn không đúng cách typedef cấu trúc để không có gì hữu ích cho trình biên dịch để "đọc".

Vì bạn đã biết câu trả lời nên theo hình thức này

typedef struct { 
... 
... 
... 
} struct-name; 

dính với điều đó.