nếu cấu trúc này được sử dụng bởi một số tệp func.c khác thì làm thế nào để làm điều đó?
Khi một kiểu được sử dụng trong một tệp (tức là tệp func.c), thì nó phải hiển thị. Cách tồi tệ nhất để làm điều đó là sao chép, dán nó vào mỗi tệp nguồn cần nó.
Cách đúng là đặt nó vào một tệp tiêu đề và bao gồm tệp tiêu đề này bất cứ khi nào cần.
chúng ta sẽ mở một tệp tiêu đề mới và khai báo cấu trúc ở đó và đưa tiêu đề đó vào func.c?
Đây là giải pháp tôi thích hơn, vì nó làm cho mã có tính mô-đun cao. Tôi sẽ viết mã cấu trúc của bạn là:
#ifndef SOME_HEADER_GUARD_WITH_UNIQUE_NAME
#define SOME_HEADER_GUARD_WITH_UNIQUE_NAME
struct a
{
int i;
struct b
{
int j;
}
};
#endif
Tôi sẽ đặt các hàm sử dụng cấu trúc này trong cùng một tiêu đề (hàm là một phần "ngữ nghĩa" của "giao diện" của nó).
Và thông thường, tôi có thể đặt tên tệp sau tên cấu trúc và sử dụng lại tên đó để chọn định nghĩa bảo vệ tiêu đề.
Nếu bạn cần khai báo một hàm bằng cách sử dụng con trỏ đến cấu trúc, bạn sẽ không cần định nghĩa cấu trúc đầy đủ. Một khai báo chuyển tiếp đơn giản như:
struct a ;
Sẽ là đủ, và nó giảm khớp nối.
hoặc chúng ta có thể xác định cấu trúc tổng trong tệp tiêu đề và bao gồm cấu trúc đó trong cả source.c và func.c không?
Đây là một cách khác, dễ dàng hơn một chút, nhưng ít mô-đun hơn: Một số mã chỉ cần cấu trúc của bạn để hoạt động sẽ vẫn phải bao gồm tất cả các loại.
Trong C ++, điều này có thể dẫn đến sự phức tạp thú vị, nhưng điều này nằm ngoài chủ đề (không có thẻ C ++), vì vậy tôi sẽ không giải thích.
thì làm thế nào để khai báo cấu trúc đó là extern trong cả hai tệp. ?
Có lẽ tôi không hiểu được vấn đề, nhưng Greg Hewgill đã có một câu trả lời rất hay trong bài đăng của mình Làm thế nào để khai báo một cấu trúc trong tiêu đề được sử dụng bởi nhiều tệp trong c? .
chúng ta sẽ đánh máy nó như thế nào?
- Nếu bạn đang sử dụng C ++ thì không.
- Nếu bạn đang sử dụng C, bạn nên.
Lý do là việc quản lý struct C có thể là một vấn đề khó khăn: Bạn phải khai báo từ khóa struct ở mọi nơi nó được sử dụng:
struct MyStruct ; /* Forward declaration */
struct MyStruct
{
/* etc. */
} ;
void doSomething(struct MyStruct * p) /* parameter */
{
struct MyStruct a ; /* variable */
/* etc */
}
Mặc dù typedef sẽ cho phép bạn viết nó mà không cần từ khóa struct.
struct MyStructTag ; /* Forward declaration */
typedef struct MyStructTag
{
/* etc. */
} MyStruct ;
void doSomething(MyStruct * p) /* parameter */
{
MyStruct a ; /* variable */
/* etc */
}
Điều quan trọng là bạn vẫn giữ tên cho cấu trúc. Viết:
typedef struct
{
/* etc. */
} MyStruct ;
sẽ chỉ tạo một cấu trúc ẩn danh với tên được đánh máy và bạn sẽ không thể khai báo nó. Vì vậy, hãy giữ nguyên định dạng sau:
typedef struct MyStructTag
{
/* etc. */
} MyStruct ;
Do đó, bạn sẽ có thể sử dụng MyStruct ở mọi nơi bạn muốn để tránh thêm từ khóa struct và vẫn sử dụng MyStructTag khi typedef không hoạt động (tức là khai báo chuyển tiếp)
Biên tập:
Đã sửa chữa giả định sai về khai báo cấu trúc C99, như nhận xét đúng của Jonathan Leffler .
Chỉnh sửa 2018-06-01:
Craig Barnes nhắc chúng ta trong nhận xét của anh ấy rằng bạn không cần phải giữ các tên riêng biệt cho tên "thẻ" struct và tên "typedef" của nó, giống như tôi đã làm ở trên để rõ ràng hơn.
Thật vậy, đoạn mã trên cũng có thể được viết là:
typedef struct MyStruct
{
/* etc. */
} MyStruct ;
IIRC, đây thực sự là những gì C ++ thực hiện với khai báo cấu trúc đơn giản hơn của nó, đằng sau hậu trường, để giữ cho nó tương thích với C:
// C++ explicit declaration by the user
struct MyStruct
{
/* etc. */
} ;
// C++ standard then implicitly adds the following line
typedef MyStruct MyStruct;
Quay lại C, tôi đã thấy cả hai cách sử dụng (tên riêng và tên giống nhau) và không có nhược điểm nào mà tôi biết, vì vậy việc sử dụng cùng một tên sẽ giúp việc đọc đơn giản hơn nếu bạn không sử dụng C riêng biệt "không gian tên" cho cấu trúc và các ký hiệu khác .
struct b
, nhưng khi đó cấu trúc của bạna
khai báo một kiểu không được sử dụng (có lẽ bạn nên xác định tên thành viênk
sau dấu ngoặc nhọn bên trong và trước dấu chấm phẩy.