2009-03-19 38 views
64

Tôi có ít hơn các kỹ năng C cấp độ mới bắt đầu và muốn biết nếu có bất kỳ "tiêu chuẩn" thực tế nào để cấu trúc một ứng dụng hơi phức tạp trong C. Ngay cả các giao diện dựa trên GUI.Tôi nên cấu trúc các dự án phức tạp như thế nào trong C?

Tôi đã luôn sử dụng mô hình OO trong Java và PHP và bây giờ tôi muốn tìm hiểu C Tôi sợ rằng tôi có thể cấu trúc các ứng dụng của mình theo cách sai. Tôi đang mất một hướng dẫn để làm theo mô-đun, tách và khô với một ngôn ngữ thủ tục.

Bạn có bất kỳ bài đọc nào để đề xuất không? Tôi không thể tìm thấy bất kỳ khung ứng dụng nào cho C, ngay cả khi tôi không sử dụng các khung công tác, tôi luôn tìm thấy các ý tưởng hay bằng cách duyệt mã của chúng.

+2

Triết lý Unix khá hữu ích để tổ chức các dự án lớn: [http://www.faqs.org/docs /artu/ch01s06.html](http://www.faqs.org/docs/artu/ch01s06.html) – newDelete

Trả lời

2

Tôi muốn đề xuất bạn kiểm tra mã của bất kỳ dự án C nguồn mở phổ biến nào, như ... hmm ... Linux kernel hoặc Git; và xem cách họ tổ chức nó.

2

Quy tắc số cho ứng dụng phức tạp: nên dễ đọc.

Để làm cho ứng dụng phức tạp trở nên đơn giản hơn, tôi sử dụng Divide and conquer.

43

Điều quan trọng là tính mô đun. Việc thiết kế, triển khai, biên dịch và bảo trì này dễ dàng hơn.

  • Xác định mô-đun trong ứng dụng của bạn, như các lớp trong ứng dụng OO.
  • Giao diện và triển khai riêng biệt cho mỗi mô-đun, chỉ đưa vào giao diện những gì cần thiết bởi các mô-đun khác. Hãy nhớ rằng không có không gian tên trong C, vì vậy bạn phải làm cho mọi thứ trong giao diện của bạn trở nên độc đáo (ví dụ, với tiền tố).
  • Ẩn các biến toàn cục trong triển khai và sử dụng các hàm truy cập để đọc/ghi.
  • Đừng nghĩ về mặt thừa kế, nhưng về thành phần. Theo nguyên tắc chung, đừng cố bắt chước C++ trong C, điều này sẽ rất khó đọc và duy trì.

Nếu bạn có thời gian để tìm hiểu, hãy xem cách ứng dụng Ada được cấu trúc, với package (giao diện mô-đun) bắt buộc và package body (triển khai mô-đun).

Đây là mã hóa.

Để duy trì (hãy nhớ rằng bạn mã một lần, nhưng bạn duy trì nhiều lần), tôi khuyên bạn nên ghi lại mã của mình; Doxygen là một lựa chọn tốt cho tôi. Tôi cũng khuyên bạn nên xây dựng một bộ kiểm thử hồi qui mạnh mẽ, cho phép bạn cấu trúc lại.

10

Số GNU coding standards đã phát triển qua một vài thập kỷ. Nên đọc chúng ngay cả khi bạn không tuân theo chúng. Suy nghĩ về những điểm được nêu trong chúng sẽ giúp bạn có cơ sở vững chắc hơn về cách cấu trúc mã của riêng bạn.

+4

Không phải ai cũng thích chúng, từ http://lxr.linux.no/linux+v2.6.29/Tài liệu/CodingStyle: "Trước hết, tôi đề nghị in ra một bản sao của các tiêu chuẩn mã hóa GNU, và KHÔNG đọc nó. Ghi chúng đi, đó là một cử chỉ tượng trưng tuyệt vời". Tôi đã không đọc chúng trong nhiều năm, nhưng Linus có một số phản đối hợp lệ. – hlovdal

+0

@hlovdal: Tất nhiên không phải ai cũng thích bất kỳ tiêu chuẩn mã hóa cụ thể nào, đó là lý do tại sao có nhiều tiêu chuẩn cho các trường hợp sử dụng tương tự. Phần quan trọng là bạn nhất quán trong các dự án của riêng bạn, rằng ít nhất một số tiêu chuẩn được theo sau, chứ không phải là sự không nhất quán về mặt thực tế. – TechZilla

27

Một quan niệm sai lầm phổ biến là các kỹ thuật OO không thể áp dụng được trong C. Hầu hết có thể - chỉ là chúng hơi khó sử dụng hơn các ngôn ngữ có cú pháp dành riêng cho công việc.

Một trong những nền tảng của thiết kế hệ thống mạnh mẽ là việc đóng gói triển khai phía sau giao diện. FILE* và các chức năng hoạt động với nó (fopen(), fread() vv) là một ví dụ tốt về cách đóng gói có thể được áp dụng trong C để thiết lập giao diện. (Tất nhiên, vì C thiếu các thông số truy cập bạn không thể thực thi mà không có ai nhìn thấy bên trong một số struct FILE, nhưng chỉ có một masochist sẽ làm như vậy.)

Nếu cần, hành vi đa hình có thể có trong C bằng cách sử dụng các bảng con trỏ hàm. Vâng, cú pháp là xấu xí nhưng hiệu quả là tương tự như chức năng ảo:

struct IAnimal { 
    int (*eat)(int food); 
    int (*sleep)(int secs); 
}; 

/* "Subclass"/"implement" IAnimal, relying on C's guaranteed equivalence 
* of memory layouts */ 
struct Cat { 
    struct IAnimal _base; 
    int (*meow)(void); 
}; 

int cat_eat(int food) { ... } 
int cat_sleep(int secs) { ... } 
int cat_meow(void) { ... } 

/* "Constructor" */ 
struct Cat* CreateACat(void) { 
    struct Cat* x = (Cat*) malloc(sizeof (struct Cat)); 
    x->_base.eat = cat_eat; 
    x->_base.sleep = cat_sleep; 
    x->meow = cat_meow; 
} 

struct IAnimal* pa = CreateACat(); 
pa->eat(42);      /* Calls cat_eat() */ 

((struct Cat*) pa)->meow();  /* "Downcast" */ 
+10

Một coder C thuần túy sẽ bị mất đọc mã này ... – mouviciel

+14

@mouviciel: Rác! Hầu hết các lập trình viên C đều hiểu các con trỏ hàm (hoặc ít nhất là chúng nên), và không có gì thực sự xảy ra ngoài điều đó ở đây. Trên Windows ít nhất, các trình điều khiển thiết bị và các đối tượng COM đều cung cấp chức năng của chúng theo cách này. –

+8

Quan điểm của tôi không phải là về sự thiếu năng lực, đó là về những biến chứng không cần thiết. Các con trỏ hàm là phổ biến cho một coder C (ví dụ, callbacks), thừa kế không phải là. Tôi thích rằng một coder mã hóa C++ trong C sử dụng thời gian của nó để tìm hiểu C hơn để xây dựng các lớp giả C++. Điều đó nói rằng, cách tiếp cận của bạn có thể hữu ích trong một số trường hợp. – mouviciel

3

Nếu bạn biết làm thế nào để cấu trúc mã của bạn trong Java hay C++, sau đó bạn có thể làm theo cùng một nguyên tắc với mã C. Sự khác biệt duy nhất là bạn không có trình biên dịch ở bên cạnh bạn và bạn cần phải làm mọi thứ một cách cẩn thận một cách cẩn thận.

Vì không có gói và lớp học, bạn cần bắt đầu bằng cách thiết kế cẩn thận mô-đun của mình. Cách tiếp cận phổ biến nhất là tạo một thư mục nguồn riêng cho từng mô-đun. Bạn cần phải dựa vào các quy ước đặt tên để phân biệt mã giữa các mô-đun khác nhau. Ví dụ tiền tố tất cả các chức năng với tên của mô-đun.

Bạn không thể có các lớp học với C, nhưng bạn có thể dễ dàng triển khai "Loại dữ liệu trừu tượng". Bạn tạo tệp .C và .H cho mọi loại dữ liệu trừu tượng. Nếu bạn thích, bạn có thể có hai tệp tiêu đề, một tệp công khai và một tệp riêng tư. Ý tưởng là tất cả các cấu trúc, hằng số và hàm cần được xuất chuyển đến tệp tiêu đề công khai.

Công cụ của bạn cũng rất quan trọng. Một công cụ hữu ích cho C là lint, có thể giúp bạn tìm thấy mùi hôi trong mã của bạn. Một công cụ khác mà bạn có thể sử dụng là Doxygen, công cụ này có thể giúp bạn tạo ra documentation.

2

Đóng gói luôn là chìa khóa để phát triển thành công, bất kể ngôn ngữ phát triển.

Bí quyết tôi đã sử dụng để giúp đóng gói các phương thức "riêng tư" trong C là không bao gồm các nguyên mẫu của chúng trong tệp ".h".

12

Tất cả câu trả lời hay.

Tôi chỉ thêm "thu nhỏ cấu trúc dữ liệu". Điều này thậm chí có thể dễ dàng hơn trong C, bởi vì nếu C++ là "C với các lớp", OOP đang cố gắng khuyến khích bạn lấy mọi danh từ/động từ trong đầu và biến nó thành một lớp/phương thức. Điều đó có thể rất lãng phí.

Ví dụ: giả sử bạn có một loạt các chỉ số nhiệt độ tại các thời điểm và bạn muốn hiển thị chúng dưới dạng biểu đồ đường trong Windows. Windows có một tin nhắn PAINT, và khi bạn nhận được nó, bạn có thể lặp qua mảng làm chức năng LineTo, mở rộng dữ liệu khi bạn chuyển đổi nó sang tọa độ pixel.

Điều mà tôi đã thấy quá nhiều lần, vì biểu đồ bao gồm các điểm và đường kẻ, mọi người sẽ xây dựng một cấu trúc dữ liệu bao gồm các đối tượng điểm và đối tượng đường thẳng, mỗi đối tượng có khả năng DrawMyself. lý thuyết rằng bằng cách nào đó "hiệu quả hơn", hoặc có thể, có thể, phải có khả năng di chuột qua các phần của biểu đồ và hiển thị dữ liệu bằng số, để chúng xây dựng các phương thức vào các đối tượng để xử lý, và , tất nhiên, liên quan đến việc tạo và xóa nhiều đối tượng hơn.

Vì vậy, bạn kết thúc với một lượng lớn mã có thể đọc được và chỉ dành 90% thời gian quản lý đối tượng.

Tất cả điều này được thực hiện dưới tên "thực hành lập trình tốt" và "hiệu quả".

Ít nhất trong C, cách đơn giản, hiệu quả sẽ rõ ràng hơn và sự cám dỗ để xây dựng kim tự tháp ít mạnh mẽ hơn.

+0

Yêu câu trả lời của bạn và điều đó hoàn toàn đúng. OOP phải chết! –

+0

@ JoSo: Tôi sử dụng OOP, nhưng tối thiểu. –

+0

Với tôi "tối thiểu" (mặc dù tôi không biết điều đó có ý nghĩa gì với bạn) không thực sự được tính là OOP, đó là Object * định hướng * lập trình - đối tượng theo mặc định. –

2

Tôi khuyên bạn nên đọc sách giáo khoa C/C++ làm bước đầu tiên. Ví dụ, C Primer Plus là một tài liệu tham khảo tốt.Xem xét các ví dụ sẽ cung cấp cho bạn và ý tưởng về cách ánh xạ OO java của bạn sang ngôn ngữ thủ tục hơn như C.

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