Làm thế nào để áp dụng nguyên tắc Phân chia giao diện trong C?


15

Tôi có một mô-đun, nói 'M', có một vài khách hàng, nói 'C1', 'C2', 'C3'. Tôi muốn phân bổ không gian tên của mô-đun M, tức là khai báo các API và dữ liệu mà nó hiển thị, vào (các) tệp tiêu đề theo cách -

  1. đối với bất kỳ khách hàng nào, chỉ có dữ liệu và API mà nó yêu cầu hiển thị; phần còn lại của không gian tên của mô-đun được ẩn khỏi máy khách, tức là tuân thủ nguyên tắc Phân chia Giao diện .
  2. một tuyên bố không được lặp lại trong nhiều tệp tiêu đề tức là không vi phạm DRY .
  3. mô-đun M không có bất kỳ phụ thuộc vào khách hàng của nó.
  4. một khách hàng không bị ảnh hưởng bởi những thay đổi được thực hiện trong các phần của mô-đun M không được sử dụng bởi nó.
  5. khách hàng hiện tại không bị ảnh hưởng bởi việc thêm (hoặc xóa) nhiều khách hàng hơn.

Hiện tại tôi giải quyết vấn đề này bằng cách chia không gian tên của mô-đun tùy thuộc vào yêu cầu của khách hàng. Ví dụ, trong hình ảnh bên dưới các phần khác nhau của không gian tên của mô-đun được yêu cầu bởi 3 máy khách của nó được hiển thị. Yêu cầu của khách hàng có sự chồng chéo. Không gian tên của mô-đun được chia thành 4 tệp tiêu đề riêng biệt - 'a', '1', '2' và '3' .

Phân vùng không gian tên mô-đun

Tuy nhiên, điều này vi phạm một số yêu cầu đã nói ở trên, ví dụ R3 và R5. Yêu cầu 3 bị vi phạm vì phân vùng này phụ thuộc vào bản chất của khách hàng; Ngoài ra, khi thêm một máy khách mới, phân vùng này thay đổi và vi phạm yêu cầu 5. Như có thể thấy ở phía bên phải của hình ảnh trên, với việc thêm một máy khách mới, không gian tên của mô-đun hiện được chia thành 7 tệp tiêu đề - 'a ',' b ',' c ',' 1 ',' 2 * ',' 3 * 'và' 4 ' . Các tệp tiêu đề có nghĩa là cho 2 trong số các máy khách cũ thay đổi, do đó kích hoạt việc xây dựng lại chúng.

Có cách nào để đạt được Phân đoạn giao diện trong C theo cách không bị hạn chế không?
Nếu có, làm thế nào bạn sẽ đối phó với ví dụ trên?

Một giải pháp giả thuyết không thực tế mà tôi tưởng tượng sẽ là -
Mô-đun có 1 tệp tiêu đề chất béo bao trùm toàn bộ không gian tên của nó. Tệp tiêu đề này được chia thành các phần có thể đánh địa chỉ và các phần phụ như trang Wikipedia. Mỗi khách hàng sau đó có một tệp tiêu đề cụ thể phù hợp với nó. Các tệp tiêu đề dành riêng cho khách hàng chỉ là một danh sách các siêu liên kết đến các phần / phần phụ của tệp tiêu đề chất béo. Và hệ thống xây dựng phải nhận ra tệp tiêu đề dành riêng cho máy khách là 'đã sửa đổi' nếu bất kỳ phần nào mà nó trỏ đến trong tiêu đề của Mô-đun được sửa đổi.


1
Tại sao vấn đề này cụ thể với C? Có phải vì C không có quyền thừa kế?
Robert Harvey

Ngoài ra, việc vi phạm ISP có làm cho thiết kế của bạn hoạt động tốt hơn không?
Robert Harvey

2
C thực sự không hỗ trợ các khái niệm OOP (như giao diện hoặc kế thừa). Chúng tôi thực hiện với các hack thô (nhưng sáng tạo). Tìm kiếm một hack để mô phỏng Giao diện. Thông thường, toàn bộ tệp tiêu đề là giao diện cho một mô-đun.
việc.bin

1
structlà những gì bạn sử dụng trong C khi bạn muốn một giao diện. Cấp, phương pháp là một chút khó khăn. Bạn có thể thấy điều này thú vị: cs.rit.edu/~ats/books/ooc.pdf
Robert Harvey

Tôi không thể đưa ra một giao diện tương đương bằng structfunction pointers.
việc.bin

Câu trả lời:


5

Phân chia giao diện, nói chung, không nên dựa trên yêu cầu của khách hàng. Bạn nên thay đổi toàn bộ cách tiếp cận để đạt được nó. Tôi có thể nói, mô đun hóa giao diện bằng cách nhóm các tính năng thành các nhóm kết hợp . Đó là nhóm dựa trên sự gắn kết của các tính năng, không phải các yêu cầu của khách hàng. Trong trường hợp đó, bạn sẽ có một bộ giao diện, I1, I2, ... vv Khách hàng C1 có thể sử dụng I2 một mình. Máy khách C2 có thể sử dụng I1 và I5, v.v ... Lưu ý rằng, nếu một máy khách sử dụng nhiều hơn một Ii, thì đó không phải là vấn đề. Nếu bạn đã phân tách giao diện thành các mô đun mạch lạc, đó là nơi cốt lõi của vấn đề.

Một lần nữa, ISP không dựa trên máy khách. Đó là về việc phân tách giao diện thành các mô-đun nhỏ hơn. Nếu điều này được thực hiện đúng cách, nó cũng sẽ đảm bảo rằng khách hàng được tiếp xúc với ít tính năng như họ cần.

Với phương pháp này, khách hàng của bạn có thể tăng lên bất kỳ số nào nhưng bạn M không bị ảnh hưởng. Mỗi khách hàng sẽ sử dụng một hoặc một số kết hợp các giao diện dựa trên nhu cầu của họ. Sẽ có trường hợp một khách hàng, C, cần bao gồm nói I1 và I3, nhưng không sử dụng tất cả các tính năng của các giao diện này? Vâng, đó không phải là một vấn đề. Nó chỉ sử dụng số lượng giao diện ít nhất.


Bạn chắc chắn có nghĩa là các nhóm rời rạc hoặc không chồng chéo , tôi giả sử?
Doc Brown

Có, rời rạc và không chồng chéo.
Nazar Merza

3

Các giao diện Tách riêng Nguyên tắc nói:

Không có khách hàng nào bị buộc phải phụ thuộc vào các phương thức mà nó không sử dụng. ISP chia các giao diện rất lớn thành các giao diện nhỏ hơn và cụ thể hơn để khách hàng sẽ chỉ phải biết về các phương thức mà họ quan tâm.

Có một vài câu hỏi chưa được trả lời ở đây. Một là:

Nhỏ như thế nào?

Bạn nói:

Hiện tại tôi xử lý vấn đề này bằng cách chia không gian tên của mô-đun tùy thuộc vào yêu cầu của khách hàng.

Tôi gọi hướng dẫn này là gõ vịt . Bạn xây dựng các giao diện chỉ hiển thị những gì khách hàng cần. Nguyên tắc phân tách giao diện không chỉ đơn giản là gõ vịt thủ công.

Nhưng ISP cũng không chỉ đơn giản là một lời kêu gọi cho các giao diện vai trò "mạch lạc" có thể được sử dụng lại. Không có thiết kế giao diện vai trò "mạch lạc" nào có thể bảo vệ hoàn hảo chống lại việc bổ sung một khách hàng mới với nhu cầu vai trò của chính nó.

ISP là một cách để cách ly khách hàng khỏi tác động của những thay đổi đối với dịch vụ. Nó được dự định để làm cho việc xây dựng diễn ra nhanh hơn khi bạn thực hiện các thay đổi. Chắc chắn nó có lợi ích khác, như không phá vỡ khách hàng, nhưng đó là điểm chính. Nếu tôi thay đổi count()chữ ký chức năng dịch vụ , thật tuyệt nếu khách hàng không sử dụng count()không cần chỉnh sửa và biên dịch lại.

Đây là lý do tại sao tôi quan tâm đến Nguyên tắc phân chia giao diện. Đó không phải là điều tôi coi niềm tin là quan trọng. Nó giải quyết một vấn đề thực sự.

Vì vậy, cách nó nên được áp dụng sẽ giải quyết một vấn đề cho bạn. Không có cách thức vơ vơ nào để áp dụng ISP mà không thể bị đánh bại chỉ bằng ví dụ đúng về một thay đổi cần thiết. Bạn có nhiệm vụ xem xét cách hệ thống thay đổi và đưa ra lựa chọn sẽ khiến mọi thứ im lặng. Hãy khám phá các tùy chọn.

Trước tiên hãy tự hỏi: việc thực hiện thay đổi giao diện dịch vụ có khó không? Nếu không, hãy ra ngoài và chơi cho đến khi bạn bình tĩnh lại. Đây không phải là một bài tập trí tuệ. Hãy chắc chắn rằng phương pháp chữa trị không tệ hơn căn bệnh này.

  1. Nếu nhiều khách hàng sử dụng cùng một tập hợp con các hàm, điều đó lập luận cho các giao diện tái sử dụng "mạch lạc". Tập hợp con có khả năng tập trung xung quanh một ý tưởng mà chúng ta có thể nghĩ về vai trò của dịch vụ đang cung cấp cho khách hàng. Thật tuyệt khi nó hoạt động. Điều này không phải lúc nào cũng hoạt động.

  2.  

    1. Nếu nhiều khách hàng sử dụng các tập hợp con khác nhau của chức năng thì có thể khách hàng thực sự đang sử dụng dịch vụ thông qua nhiều vai trò. Điều đó ổn nhưng nó làm cho các vai trò khó thấy. Tìm họ và cố gắng trêu chọc họ. Điều đó có thể đưa chúng tôi trở lại trong trường hợp 1. Khách hàng chỉ cần sử dụng dịch vụ thông qua nhiều giao diện. Vui lòng không bắt đầu truyền dịch vụ. Nếu bất cứ điều gì có nghĩa là chuyển dịch vụ vào máy khách nhiều lần. Điều đó hoạt động nhưng nó khiến tôi đặt câu hỏi nếu dịch vụ không phải là một quả bóng bùn lớn cần phải phá vỡ.

    2. Nếu nhiều khách hàng sử dụng các tập hợp con khác nhau nhưng bạn không thấy các vai trò thậm chí cho phép các khách hàng có thể sử dụng nhiều hơn một thì bạn không có gì tốt hơn là gõ vịt để thiết kế giao diện của bạn xung quanh. Cách thiết kế giao diện này đảm bảo rằng máy khách không tiếp xúc với ngay cả một chức năng mà nó không sử dụng nhưng nó gần như đảm bảo rằng việc thêm một máy khách mới sẽ luôn liên quan đến việc thêm một giao diện mới mà trong khi thực hiện dịch vụ không cần biết về nó giao diện tổng hợp các giao diện vai trò sẽ. Chúng tôi chỉ đơn giản là đánh đổi một nỗi đau cho người khác.

  3. Nếu nhiều khách hàng sử dụng các tập hợp con khác nhau, chồng chéo, các khách hàng mới dự kiến ​​sẽ thêm vào đó sẽ cần các tập hợp con không thể đoán trước và bạn không muốn chia tay dịch vụ sau đó xem xét một giải pháp chức năng hơn. Vì hai tùy chọn đầu tiên không hoạt động và bạn thực sự ở một nơi tồi tệ, nơi không có gì theo một mô hình và sẽ có nhiều thay đổi hơn, sau đó xem xét việc cung cấp cho mỗi chức năng đó là giao diện riêng. Kết thúc ở đây không có nghĩa là ISP đã thất bại. Nếu bất cứ điều gì thất bại, đó là mô hình hướng đối tượng. Giao diện phương thức duy nhất theo ISP trong cực đoan. Đó là một chút gõ bàn phím nhưng bạn có thể thấy điều này đột nhiên làm cho các giao diện có thể sử dụng lại. Một lần nữa, hãy chắc chắn rằng không có

Vì vậy, hóa ra họ có thể nhận được rất nhỏ thực sự.

Tôi đã đặt câu hỏi này như một thách thức để áp dụng ISP trong những trường hợp cực đoan nhất. Nhưng hãy nhớ rằng cực đoan là tốt nhất nên tránh. Trong một thiết kế được cân nhắc kỹ lưỡng áp dụng các nguyên tắc RẮN khác, các vấn đề này thường không xảy ra hoặc không quan trọng, gần như nhiều.


Một câu hỏi chưa được trả lời là:

Ai sở hữu các giao diện này?

Lâu dần tôi thấy các giao diện được thiết kế với tâm lý mà tôi gọi là "thư viện". Tất cả chúng ta đều có lỗi về mã hóa khỉ-khỉ-do bạn đang làm gì đó bởi vì đó là cách bạn đã thấy nó được thực hiện. Chúng tôi có tội với điều tương tự với giao diện.

Khi tôi nhìn vào một giao diện được thiết kế cho một lớp trong thư viện tôi từng nghĩ: ồ, những người này là ưu. Đây phải là cách đúng đắn để làm một giao diện. Điều tôi đã không hiểu là ranh giới thư viện có nhu cầu và vấn đề riêng. Đối với một điều, một thư viện hoàn toàn không biết gì về thiết kế của khách hàng. Không phải mọi ranh giới đều giống nhau. Và đôi khi ngay cả cùng một ranh giới có những cách khác nhau để vượt qua nó.

Dưới đây là hai cách đơn giản để xem thiết kế giao diện:

  • Giao diện sở hữu dịch vụ. Một số người thiết kế mọi giao diện để phơi bày mọi thứ mà một dịch vụ có thể làm. Bạn thậm chí có thể tìm thấy các tùy chọn tái cấu trúc trong IDE sẽ viết giao diện cho bạn bằng cách sử dụng bất kỳ lớp nào bạn cung cấp cho nó.

  • Giao diện khách hàng sở hữu. ISP dường như lập luận rằng điều này là đúng và sở hữu dịch vụ là sai. Bạn nên chia nhỏ mọi giao diện với nhu cầu của khách hàng. Vì khách hàng sở hữu giao diện nên nó xác định nó.

Vậy ai đúng?

Xem xét các plugin:

nhập mô tả hình ảnh ở đây

Ai sở hữu các giao diện ở đây? Các khách hàng? Các dịch vụ?

Hóa ra cả hai.

Màu sắc ở đây là các lớp. Lớp màu đỏ (phải) không cần biết gì về lớp màu xanh lá cây (bên trái). Lớp màu xanh lá cây có thể được thay đổi hoặc thay thế mà không cần chạm vào lớp màu đỏ. Bằng cách đó, bất kỳ lớp màu xanh lá cây có thể được cắm vào lớp màu đỏ.

Tôi muốn biết những gì cần biết về những gì và những gì không nên biết. Đối với tôi, "những gì biết về cái gì?", Là câu hỏi kiến ​​trúc quan trọng nhất.

Hãy làm cho một số từ vựng rõ ràng:

[Client] --> [Interface] <|-- [Service]

----- Flow ----- of ----- control ---->

Một khách hàng là một cái gì đó sử dụng.

Một dịch vụ là một cái gì đó được sử dụng.

Interactor xảy ra là cả hai.

ISP cho biết chia tay giao diện cho khách hàng. Tốt thôi, hãy áp dụng điều đó ở đây:

  • Presenter(một dịch vụ) không nên ra lệnh cho Output Port <I>giao diện. Giao diện nên được thu hẹp theo những gì Interactor(ở đây đóng vai trò là khách hàng) cần. Điều đó có nghĩa là giao diện BIẾT về Interactorvà, để theo ISP, phải thay đổi với nó. Và điều này là tốt.

  • Interactor(ở đây hoạt động như một dịch vụ) không nên ra lệnh cho Input Port <I>giao diện. Giao diện nên được thu hẹp theo những gì Controller(một khách hàng) cần. Điều đó có nghĩa là giao diện BIẾT về Controllervà, để theo ISP, phải thay đổi với nó. Và điều này là không tốt.

Lớp thứ hai không ổn vì lớp màu đỏ không được biết về lớp màu xanh lá cây. Vậy ISP có sai không? Vâng tốt bụng. Không có nguyên tắc là tuyệt đối. Đây là một trường hợp mà những kẻ ngốc thích giao diện hiển thị mọi thứ mà dịch vụ có thể làm được là đúng.

Ít nhất, họ đúng nếu Interactorkhông làm gì khác ngoài trường hợp sử dụng này cần. Nếu việc Interactornày xảy ra đối với các trường hợp sử dụng khác thì không có lý do gì Input Port <I>để biết về chúng. Không chắc chắn tại sao Interactorkhông thể chỉ tập trung vào một Ca sử dụng vì vậy đây không phải là vấn đề, nhưng mọi thứ xảy ra.

Nhưng input port <I>giao diện đơn giản là không thể tự nô lệ cho Controllermáy khách và đây là một plugin thực sự. Đây là ranh giới của 'thư viện'. Một cửa hàng lập trình hoàn toàn khác có thể viết lớp màu xanh lá cây nhiều năm sau khi lớp màu đỏ được xuất bản.

Nếu bạn đang vượt qua ranh giới 'thư viện' và bạn cảm thấy cần phải áp dụng ISP mặc dù bạn không sở hữu giao diện ở phía bên kia, bạn sẽ phải tìm cách thu hẹp giao diện mà không thay đổi giao diện.

Một cách để kéo nó ra là một bộ chuyển đổi. Đặt nó giữa khách hàng thích ControlerInput Port <I>giao diện. Bộ điều hợp chấp nhận Interactornhư một Input Port <I>và ủy thác nó hoạt động với nó. Tuy nhiên, nó chỉ hiển thị những gì khách hàng Controllercần thông qua giao diện vai trò hoặc giao diện thuộc sở hữu của lớp màu xanh lá cây. Bộ điều hợp không tự đi theo ISP nhưng cho phép lớp phức tạp hơn thích Controllerthưởng thức ISP. Điều này hữu ích nếu có ít bộ điều hợp hơn so với các máy khách như Controllervậy sử dụng chúng và khi bạn ở trong tình huống bất thường khi bạn vượt qua ranh giới thư viện và mặc dù được xuất bản, thư viện sẽ không ngừng thay đổi. Nhìn vào bạn Firefox. Bây giờ những thay đổi đó chỉ phá vỡ bộ điều hợp của bạn.

Vì vậy, điều này có nghĩa là gì? Điều đó có nghĩa là bạn không cung cấp đủ thông tin để tôi nói cho bạn biết bạn nên làm gì. Tôi không biết nếu không theo dõi ISP sẽ gây ra sự cố cho bạn. Tôi không biết nếu làm theo nó sẽ không gây ra cho bạn nhiều vấn đề hơn.

Tôi biết bạn đang tìm kiếm một nguyên tắc hướng dẫn đơn giản. ISP cố gắng để được điều đó. Nhưng nó để lại rất nhiều không trả lời. Tôi tin vào nó. Có, vui lòng không ép buộc khách hàng phụ thuộc vào các phương pháp mà họ không sử dụng mà không có lý do chính đáng!

Nếu bạn có lý do chính đáng, chẳng hạn như thiết kế của bạn để chấp nhận plugin, thì hãy lưu ý đến các vấn đề không tuân theo nguyên nhân của ISP (khó thay đổi mà không phá vỡ máy khách) và cách để giảm thiểu chúng (giữ Interactorhoặc ít nhất là Input Port <I>tập trung vào một ổn định trường hợp sử dụng).


Cảm ơn các đầu vào. Tôi có một mô-đun cung cấp dịch vụ có nhiều khách hàng. Không gian tên của nó có các ranh giới mạch lạc logic nhưng nhu cầu của khách hàng cắt ngang các ranh giới logic này. Do đó, việc phân chia không gian tên trên cơ sở các ranh giới logic không giúp ích gì cho ISP. Do đó, tôi đã phân chia không gian tên trên cơ sở nhu cầu của khách hàng như được hiển thị trong sơ đồ trong câu hỏi. Nhưng điều này làm cho nó phụ thuộc vào khách hàng và cách kết nối khách hàng kém với dịch vụ, vì khách hàng có thể được thêm / xóa tương đối thường xuyên, nhưng những thay đổi trong dịch vụ sẽ rất ít.
việc.bin

Bây giờ tôi đang nghiêng về dịch vụ cung cấp giao diện béo, như trong không gian tên đầy đủ của nó và tùy thuộc vào khách hàng truy cập các dịch vụ này thông qua các bộ điều hợp cụ thể của khách hàng. Trong thuật ngữ C đó sẽ là một tập tin của hàm bao hàm do khách hàng sở hữu. Những thay đổi trong dịch vụ sẽ buộc biên dịch lại bộ điều hợp nhưng không nhất thiết phải là máy khách. .. <
contd

<tiếp tục (lập trình viên) trong việc duy trì các bộ điều hợp.
việc.bin

Giải pháp hiện tại của tôi đáp ứng nhu cầu của tôi bây giờ, cách tiếp cận mới sẽ tốn nhiều công sức hơn và có thể vi phạm YAGNI. Tôi sẽ phải cân nhắc những ưu và nhược điểm của từng phương pháp và quyết định cách nào để đi đến đây.
việc.bin

1

Vì vậy, điểm này:

existent clients are unaffected by the addition (or deletion) of more clients.

Cho rằng bạn đang vi phạm một nguyên tắc quan trọng khác đó là YAGNI. Tôi sẽ quan tâm đến nó khi tôi có hàng trăm khách hàng. Suy nghĩ về một cái gì đó ở phía trước và sau đó nó sẽ chỉ ra rằng bạn không có bất kỳ khách hàng bổ sung nào cho mã này đánh bại mục đích.

Thứ hai

 partitioning depends on the nature of clients

Tại sao mã của bạn không sử dụng DI, đảo ngược phụ thuộc, không có gì, không có gì trong thư viện của bạn nên phụ thuộc vào bản chất khách hàng của bạn.

Cuối cùng, có vẻ như bạn cần lớp bổ sung theo mã của mình để phục vụ nhu cầu cho các thứ chồng chéo (DI để mã mặt trước của bạn chỉ phụ thuộc vào lớp bổ sung này và khách hàng của bạn chỉ phụ thuộc vào giao diện mặt trước của bạn) theo cách bạn đánh bại DRY.
Điều này bạn sẽ od nó thực sự. Vì vậy, bạn tạo ra những thứ tương tự mà bạn sử dụng trong lớp mô-đun yor bên dưới mô-đun khác. Cách này có lớp bên dưới bạn đạt được:

đối với bất kỳ khách hàng nào, chỉ có dữ liệu và API mà nó yêu cầu hiển thị; phần còn lại của không gian tên của mô-đun được ẩn khỏi máy khách, tức là tuân thủ nguyên tắc Phân chia Giao diện.

Đúng

một tuyên bố không được lặp lại trong nhiều tệp tiêu đề tức là không vi phạm DRY. mô-đun M không có bất kỳ phụ thuộc vào khách hàng của nó.

Đúng

một khách hàng không bị ảnh hưởng bởi những thay đổi được thực hiện trong các phần của mô-đun M không được sử dụng bởi nó.

Đúng

khách hàng hiện tại không bị ảnh hưởng bởi việc thêm (hoặc xóa) nhiều khách hàng hơn.

Đúng


1

Thông tin tương tự như được cung cấp trong khai báo luôn được lặp lại trong định nghĩa. Đó chỉ là cách ngôn ngữ này hoạt động. Ngoài ra, việc lặp lại một khai báo trong nhiều tệp tiêu đề không vi phạm DRY . Đây là một kỹ thuật được sử dụng khá phổ biến (ít nhất là trong thư viện tiêu chuẩn).

Lặp lại tài liệu hoặc việc thực hiện sẽ vi phạm DRY .

Tôi sẽ không bận tâm đến điều này trừ khi mã khách hàng không được viết bởi tôi.


0

Tôi từ chối sự nhầm lẫn của tôi. Tuy nhiên ví dụ thực tế của bạn rút ra một giải pháp trong đầu tôi. Nếu tôi có thể nói thành lời của mình: tất cả các phân vùng trong mô-đun Mcó mối quan hệ nhiều đến nhiều với bất kỳ và tất cả các máy khách.

Cấu trúc mẫu

M.h      // fat header
 - P1    // Partition 1
 - P2    // ... 2
   - P21 // ... 2 section 1
 - P3    // ... 3
C1.c     // Client 1 (Needs to include P1, P3)
C2.c     // ... 2 (Needs to include P2)
C3.c     // ... 3 (Needs to include P1, P21, P3)

À

#ifdef P1
#define _PREF_ P1_             // Define Prefix ("PREF") = P1_
 void _PREF_init();            // Some partition specific function
#endif /* P1 */

#ifdef P2
#define _PREF_ P2_
 void _PREF_init();
#endif /* P2 */

#if defined(P21) || defined (P2) // Part 2.1
#define _PREF_ P2_1_
 void _PREF_oddone();
#endif /* P21 */

#ifdef P3
#define _PREF_ P3_
 void _PREF_init();
#endif /* P3 */

Mc

Trong tệp Mc, bạn thực sự sẽ không phải sử dụng #ifdefs vì những gì bạn đặt trong tệp .c không ảnh hưởng đến các tệp khách hàng miễn là các chức năng mà tệp khách hàng sử dụng được xác định.

#include "M.h"
#define _PREF_ P1_        
void _PREF_init() { ... };

#define _PREF_ P2_
void _PREF_init() { ... }

#define _PREF_ P2_1_
void _PREF_oddone() { ... }

#define _PREF_ P3_
void _PREF_init() { ... }

C1.c

#define P1     // "invite" P1
#define P3     // "invite" P3
#include "M.h" // Open the door, but only the invited come in.

void main()
{
    P1_init();
    //P2_init();
    //P2_1_oddone();
    P3_init();
}

Cc.c

#define P2
#include "M.h

void main()
{
    //P1_init();
    P2_init();
    P2_1_oddone();
    //P3_init();
}

C3.c

#define P1
#define P21
#define P3  
#include "M.h" 

void main()
{
    P1_init();
    //P2_init();
    P2_1_oddone();
    P3_init();
}

Một lần nữa, tôi không chắc đây có phải là điều bạn đang hỏi không. Vì vậy, mang nó với một hạt muối.


Mc trông như thế nào? Bạn có định nghĩa P1_init() P2_init() ?
việc.bin

@ work.bin Tôi đoán Mc sẽ trông giống như một tệp .c đơn giản, ngoại trừ việc xác định không gian tên giữa các hàm.
Sanchke Dellowar

Giả sử tồn tại cả C1 và C2 - những gì P1_init()P2_init()liên kết đến?
việc.bin

Trong tệp Mh / Mc, Bộ tiền xử lý sẽ thay thế _PREF_bằng bất cứ thứ gì được xác định lần cuối. Vì vậy, _PREF_init()sẽ là P1_init()vì tuyên bố #define cuối cùng. Sau đó, câu lệnh xác định tiếp theo sẽ đặt PREF bằng P2_, do đó tạo ra P2_init().
Sanchke Dellowar
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.