Tại sao trình biên dịch không thể tự nhập tệp tiêu đề hai lần?


13

Mới sử dụng C ++! Vì vậy, tôi đã đọc nó: http://www.learncpp.com/cpp-tutorial/110-a-first-look-at-the-pre Processor /

Bảo vệ tiêu đề

Vì các tệp tiêu đề có thể bao gồm các tệp tiêu đề khác, nên có thể kết thúc trong tình huống tệp tiêu đề được đưa vào nhiều lần.

Vì vậy, chúng tôi thực hiện các chỉ thị tiền xử lý để tránh điều này. Nhưng tôi không chắc chắn - tại sao trình biên dịch không thể ... không nhập cùng một thứ hai lần?

Cho rằng các bộ bảo vệ tiêu đề là tùy chọn (nhưng rõ ràng là một cách thực hành tốt), nó gần như khiến tôi nghĩ rằng có những kịch bản khi bạn muốn nhập một cái gì đó hai lần. Mặc dù tôi không thể nghĩ ra bất kỳ kịch bản nào như vậy cả. Có ý kiến ​​gì không?


Trên trình biên dịch MS có #pragma oncetrình biên dịch chỉ bao gồm tệp đó một lần.
CodeInChaos

Câu trả lời:


27

Họ có thể, như thể hiện bởi các ngôn ngữ mới mà.

Nhưng một quyết định thiết kế đã được đưa ra từ nhiều năm trước (khi trình biên dịch C có nhiều giai đoạn độc lập) và bây giờ để duy trì khả năng tương thích, bộ xử lý trước phải hành động theo một cách nhất định để đảm bảo mã cũ biên dịch như mong đợi.

Vì C ++ kế thừa cách nó xử lý các tệp tiêu đề từ C, nó duy trì các kỹ thuật tương tự. Chúng tôi đang hỗ trợ một quyết định thiết kế cũ. Nhưng thay đổi cách thức hoạt động thì quá nhiều rủi ro có thể bị phá vỡ. Vì vậy, bây giờ chúng tôi phải dạy cho người dùng mới ngôn ngữ cách sử dụng bao gồm các vệ sĩ.

Có một số thủ thuật với các tệp tiêu đề là bạn cố tình đưa nó nhiều lần (điều này thực sự cung cấp một tính năng hữu ích). Mặc dù nếu chúng tôi thiết kế lại mô hình từ đầu, chúng tôi có thể thực hiện điều này theo cách không mặc định để bao gồm các tệp.


7

Nó sẽ không biểu cảm bằng cách khác, cho rằng họ đã chọn duy trì khả năng tương thích với C và do đó tiếp tục với một bộ xử lý trước hơn là một hệ thống đóng gói truyền thống.

Một điều khiến tôi suy nghĩ là tôi đã có một dự án là API. Tôi đã có hai tập tin tiêu đề x86lib.hx86lib_internal.h. Vì nội bộ rất lớn, tôi đã tách các bit "công khai" thành x86lib.h để người dùng không phải dành thêm thời gian để biên dịch.

Điều này đã giới thiệu một vấn đề buồn cười với các phụ thuộc mặc dù vậy cuối cùng tôi đã có một luồng đi như thế này trong x86lib_iternal

  1. Đặt định nghĩa tiền xử lý NỘI BỘ
  2. Bao gồm x86lib.h (thông minh để hành động theo một cách nhất định khi nội bộ được xác định)
  3. Làm một số thứ và giới thiệu một số thứ được sử dụng trong x86lib.h
  4. Đặt SAU tiền xử lý xác định
  5. Bao gồm x86lib.h một lần nữa (lần này nó sẽ bỏ qua mọi thứ trừ phần AFTER được tách riêng phụ thuộc vào các phần tử của x86lib_iternal

Tôi sẽ không nói đó là cách tốt nhất để nói về nó, nhưng nó đã đạt được những gì tôi muốn.


0

Một khó khăn với loại trừ tiêu đề trùng lặp tự động là tiêu chuẩn C tương đối im lặng về chủ đề bao gồm tên tệp có nghĩa là gì. Ví dụ: giả sử tệp chính đang được biên dịch chứa các lệnh #include "f1.h"#include "f2.h"và các tệp được tìm thấy cho các lệnh đó đều chứa #include "f3.h". Nếu f1.hf2.hnằm trong các thư mục khác nhau, nhưng được tìm thấy bằng cách tìm kiếm bao gồm các đường dẫn, thì sẽ không rõ các #includechỉ thị trong các tệp đó được dự định tải cùng một f3.htệp hoặc các tệp khác nhau.

Mọi thứ thậm chí còn tồi tệ hơn nếu người ta thêm vào các khả năng bao gồm các tệp bao gồm các đường dẫn tương đối. Trong một số trường hợp trong đó các tệp tiêu đề sử dụng các đường dẫn tương đối cho các lệnh được lồng vào nhau và trong đó người ta muốn tránh thực hiện bất kỳ thay đổi nào đối với các tệp tiêu đề được cung cấp, có thể cần phải có một tệp tiêu đề được sao chép ở nhiều vị trí trong cấu trúc thư mục của dự án. Mặc dù có nhiều bản sao vật lý của tệp tiêu đề đó tồn tại, chúng vẫn nên được xem xét về mặt ngữ nghĩa như thể chúng là một tệp duy nhất.

Nếu lệnh #pragma oncecho phép một mã định danh tuân theo once, với ngữ nghĩa mà trình biên dịch sẽ bỏ qua tệp nếu mã định danh khớp với một từ một lệnh được gặp trước đó #pragma once, thì ngữ nghĩa sẽ không rõ ràng; một trình biên dịch có thể cho biết rằng một lệnh #includesẽ tải cùng một #pragma oncetệp được đánh dấu như trước đó, nó có thể tiết kiệm một chút thời gian bằng cách bỏ qua tệp mà không mở lại, nhưng phát hiện như vậy sẽ không quan trọng về mặt ngữ nghĩa vì tệp có bị bỏ qua hay không hoặc không phải tên tệp được công nhận là khớp. Tôi không biết về bất kỳ trình biên dịch làm việc theo cách đó, tuy nhiên. Có một trình biên dịch quan sát xem một tệp có khớp với mẫu đó #ifndef someIdentifier / #define someIdentifier / #endif [for that ifndef] / nothing followinghay không và xử lý một thứ tương đương như trên #pragma once someIdentifiernếusomeIdentifier vẫn được xác định, về cơ bản là tốt.

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.