Sự khác biệt giữa #include <filename> và #include vào tên tập tin là gì?


2357

Trong ngôn ngữ lập trình C và C ++, sự khác biệt giữa sử dụng dấu ngoặc góc và sử dụng dấu ngoặc kép trong includecâu lệnh, như sau là gì?

  1. #include <filename>
  2. #include "filename"



Đối với hành vi của Visual Studio, vui lòng kiểm tra: docs.microsoft.com/en-us/cpp/pre Processor / 21
smwikipedia

Câu trả lời:


1405

Trong thực tế, sự khác biệt nằm ở vị trí mà bộ tiền xử lý tìm kiếm tệp được bao gồm.

Đối với #include <filename>các tìm kiếm tiền xử lý theo cách phụ thuộc triển khai, thông thường trong các thư mục tìm kiếm được chỉ định trước bởi trình biên dịch / IDE. Phương pháp này thường được sử dụng để bao gồm các tệp tiêu đề thư viện tiêu chuẩn.

Đối với #include "filename"các bộ xử lý tiền tìm kiếm trước tiên trong cùng thư mục với tệp chứa lệnh, sau đó theo đường dẫn tìm kiếm được sử dụng cho #include <filename>biểu mẫu. Phương pháp này thường được sử dụng để bao gồm các tệp tiêu đề do lập trình viên xác định.

Một mô tả đầy đủ hơn có sẵn trong tài liệu GCC trên các đường dẫn tìm kiếm .


135
Câu lệnh: "tìm kiếm tiền xử lý trong cùng một thư mục ..." có thể đúng trong thực tế nhưng tiêu chuẩn nói rằng tệp nguồn được đặt tên là "được tìm kiếm theo cách xác định thực hiện". Xem câu trả lời từ piCookie.
Richard Corden

60
Mặc dù câu trả lời của bạn có vẻ là "đúng", bởi vì đây là cách thực hiện theo nhiều quy ước, bạn nên xem xét kỹ câu trả lời của aib và piCookie. Cả hai đều chỉ ra (được hỗ trợ bởi từ ngữ của tiêu chuẩn C) rằng sự khác biệt thực sự là bao gồm một "tiêu đề" so với việc bao gồm một "tệp nguồn" (và không, điều này không có nghĩa là ".h" so với ". c "). "Tệp nguồn" trong ngữ cảnh này có thể là (và thường là, và hầu như luôn luôn là) một tệp ".h". Một tiêu đề không nhất thiết phải là một tệp (một trình biên dịch có thể bao gồm một tiêu đề được mã hóa tĩnh, không phải trong một tệp).
Dan Mould

5
"... bộ tiền xử lý tìm kiếm trong cùng thư mục với tệp được biên dịch cho tệp được bao gồm." Tuyên bố này không hoàn toàn chính xác. Tôi quan tâm đến câu hỏi này vì tôi tò mò câu trả lời thực sự là gì, nhưng tôi biết điều này không đúng vì ít nhất là với gcc khi bạn chỉ định một đường dẫn bao gồm bổ sung với -I sẽ tìm kiếm các tệp được chỉ định với tên tệp #include ". h "
Gabriel Nam

9
Những người không thích câu trả lời, xin vui lòng, đưa ra một ví dụ thực tế, nơi nó sai.
0kcats

1
Chắc chắn, gần đây tôi đã trộn các cú pháp này khi bao gồm các tiêu đề từ thư viện 'cùng' và kết thúc với các lỗi xác định lại. Nếu tôi hiểu chính xác, hãy #include <...>sử dụng gói được cài đặt trên hệ thống và #include "..."sử dụng phiên bản kho lưu trữ gần đó. Tôi có thể có những người ngược. Dù bằng cách nào, bộ bảo vệ bao gồm trong tiêu đề được đóng gói có tiền tố gạch dưới. (Nó có thể là một quy ước cho các gói hoặc có thể là một cách cố tình ngăn chặn việc trộn lẫn cả hai, mặc dù vòng loại phiên bản sẽ có ý nghĩa hơn đối với tôi.)
John P

714

Cách duy nhất để biết là đọc tài liệu triển khai của bạn.

Trong tiêu chuẩn C , mục 6.10.2, đoạn 2 đến 4 trạng thái:

  • Một chỉ thị tiền xử lý của mẫu

    #include <h-char-sequence> new-line

    tìm kiếm một chuỗi các vị trí được xác định thực hiện cho một tiêu đề được xác định duy nhất bởi trình tự được chỉ định giữa <và các >dấu phân cách và gây ra sự thay thế của lệnh đó bởi toàn bộ nội dung của tiêu đề . Làm thế nào các địa điểm được chỉ định hoặc tiêu đề được xác định là xác định thực hiện.

  • Một chỉ thị tiền xử lý của mẫu

    #include "q-char-sequence" new-line

    gây ra sự thay thế của lệnh đó bởi toàn bộ nội dung của tệp nguồn được xác định bởi trình tự được chỉ định giữa các "dấu phân cách. Tệp nguồn được đặt tên được tìm kiếm theo cách xác định thực hiện. Nếu tìm kiếm này không được hỗ trợ hoặc nếu tìm kiếm thất bại, lệnh sẽ được xử lý lại như thể nó đã đọc

    #include <h-char-sequence> new-line

    với chuỗi chứa giống hệt nhau (bao gồm các >ký tự, nếu có) từ chỉ thị ban đầu.

  • Một chỉ thị tiền xử lý của mẫu

    #include pp-tokens new-line

    (không phù hợp với một trong hai hình thức trước đó) được cho phép. Các mã thông báo tiền xử lý sau includetrong lệnh được xử lý giống như trong văn bản thông thường. (Mỗi mã định danh hiện được xác định là tên macro được thay thế bằng danh sách mã thông báo tiền xử lý thay thế.) Lệnh được tạo sau tất cả các thay thế sẽ khớp với một trong hai dạng trước đó. Phương pháp mà theo đó một chuỗi các tiền xử lý tokens giữa <và một >cặp thẻ tiền xử lý hoặc một cặp "nhân vật được kết hợp thành một tên tiêu đề đơn tiền xử lý mã thông báo là thực hiện xác định.

Định nghĩa:

  • h-char: bất kỳ thành viên nào của bộ ký tự nguồn trừ ký tự dòng mới và >

  • q-char: bất kỳ thành viên nào của bộ ký tự nguồn trừ ký tự dòng mới và "


108
Có liên quan: triển khai trong g ++trực quan c ++
Alexander Malakhov

27
@piCookie cả <tên tệp> và "tên tệp" tìm kiếm cho các địa điểm được xác định thực hiện. Vì vậy, sự khác biệt là gì ?
onmyway133

15
@Stefan, tôi chỉ trích dẫn tiêu chuẩn không nói gì về INCLUDE_PATH. Việc thực hiện của bạn có thể làm điều đó, còn tôi thì không. Câu hỏi ban đầu là chung chung C và không cụ thể là gcc (mà tôi không nghĩ sử dụng INCLUDE_PATH) hoặc Microsoft C (mà tôi nghĩ là như vậy) hoặc bất kỳ câu hỏi nào khác, vì vậy không thể trả lời chung chung mà phải tham khảo từng tài liệu triển khai.
piCookie

12
Như với tất cả các tình huống này, các ví dụ cụ thể (đặc biệt là các tình huống phổ biến) rất hữu ích và được đánh giá cao không kém. Những câu trả lời chung chung không cần thiết không có nhiều sử dụng thực tế.
vargonia

132
"Đây là cách tiêu chuẩn C có thể dài dòng và không trả lời câu hỏi của bạn"
anatolyg

287

Chuỗi các ký tự giữa <và> duy nhất đề cập đến một tiêu đề, không nhất thiết phải là một tệp. Việc triển khai là khá nhiều miễn phí để sử dụng chuỗi ký tự như họ muốn. (Tuy nhiên, hầu hết, chỉ coi nó như một tên tệp và thực hiện tìm kiếm trong đường dẫn bao gồm , như trạng thái bài viết khác.)

Nếu #include "file"biểu mẫu được sử dụng, trước tiên, việc triển khai sẽ tìm một tệp có tên đã cho, nếu được hỗ trợ. Nếu không (được hỗ trợ) hoặc nếu tìm kiếm thất bại, việc triển khai sẽ hoạt động như thể #include <file>hình thức ( ) khác đã được sử dụng.

Ngoài ra, một hình thức thứ ba tồn tại và được sử dụng khi #includechỉ thị không khớp với một trong các hình thức trên. Trong biểu mẫu này, một số tiền xử lý cơ bản (như mở rộng macro) được thực hiện trên "toán hạng" của lệnh #includevà kết quả dự kiến ​​sẽ khớp với một trong hai dạng khác.


50
+1, đây có lẽ là câu trả lời ngắn gọn và chính xác nhất ở đây. Theo tiêu chuẩn (mà piCookie trích dẫn từ trong câu trả lời của anh ấy), sự khác biệt thực sự duy nhất là "tiêu đề" so với "tệp nguồn". Cơ chế tìm kiếm được xác định theo một trong hai cách. Sử dụng dấu ngoặc kép có nghĩa là bạn dự định bao gồm "tệp nguồn", trong khi dấu ngoặc góc có nghĩa là bạn dự định bao gồm một "tiêu đề", như bạn nói, có thể hoàn toàn không phải là một tệp.
Dan Mould

3
Xem bình luận của Dan Moulding cho câu trả lời của Quest49; tiêu đề tiêu chuẩn không phải ở dạng tệp, chúng có thể được tích hợp sẵn.
aib

10
Tôi đã đọc "tiêu đề tiêu chuẩn này không phải ở dạng tệp" trong một thập kỷ. Muốn cung cấp một ví dụ thực tế?
Maxim Egorushkin

12
@Maxim Yegorushkin: Tôi cũng không thể nghĩ ra bất kỳ ví dụ thực tế nào hiện có; tuy nhiên, không có trình biên dịch C11 hoàn chỉnh nào có thể tồn tại cho MS-DOS trừ khi các tiêu đề không phải là tệp. Điều này là do một số tên tiêu đề C11 không tương thích với giới hạn tên tệp "8.3" MS-DOS.
Dan Mould

18
@MaximEgorushkin: Trình biên dịch VAX / VMS C giữ tất cả các tiêu đề thư viện thời gian chạy C trong một tệp thư viện văn bản duy nhất (tương tự như một kho lưu trữ unix) và sử dụng chuỗi giữa <>làm khóa để lập chỉ mục vào thư viện.
Adrian McCarthy

117

Một số câu trả lời hay ở đây làm tham chiếu đến tiêu chuẩn C nhưng quên tiêu chuẩn POSIX, đặc biệt là hành vi cụ thể của lệnh c99 (ví dụ: trình biên dịch C) .

Theo Thông số kỹ thuật cơ sở nhóm mở số 7 ,

-Tôi thư mục

Thay đổi thuật toán tìm kiếm các tiêu đề có tên không phải là tên đường dẫn tuyệt đối để tìm trong thư mục được đặt tên theo tên đường dẫn thư mục trước khi tìm ở các vị trí thông thường. Do đó, các tiêu đề có tên được đặt trong dấu ngoặc kép ("") sẽ được tìm kiếm đầu tiên trong thư mục của tệp có dòng #include , sau đó trong các thư mục có tên trong tùy chọn -I và cuối cùng ở các vị trí thông thường. Đối với các tiêu đề có tên được đặt trong dấu ngoặc nhọn ("<>"), tiêu đề chỉ được tìm kiếm trong các thư mục có tên trong tùy chọn -I và sau đó ở các vị trí thông thường. Các thư mục có tên trong tùy chọn -I sẽ được tìm kiếm theo thứ tự được chỉ định.Lệnh gọi c99 .

Vì vậy, trong môi trường tuân thủ POSIX, với trình biên dịch C tuân thủ POSIX, #include "file.h"có khả năng sẽ tìm kiếm ./file.htrước, .thư mục chứa tệp có #includecâu lệnh ở đâu, trong khi #include <file.h>, có khả năng sẽ tìm kiếm /usr/include/file.htrước, /usr/includehệ thống của bạn được xác định ở đâu địa điểm thông thường cho các tiêu đề (dường như không được xác định bởi POSIX).


1
Nguồn chính xác của văn bản là gì? Có phải từ một phần quy phạm của IEEE Std 1003.1, 2013?
osgx

7
@osgx: từ ngữ đó (hoặc một cái gì đó cực kỳ giống nhau) được tìm thấy trong đặc tả POSIX cho c99- đó là tên POSIX cho trình biên dịch C. (Tiêu chuẩn POSIX 2008 khó có thể tham khảo C11; bản cập nhật 2013 cho POSIX 2008 không thay đổi tiêu chuẩn C mà nó đề cập đến.)
Jonathan Leffler

1
Đây cũng là suy nghĩ đầu tiên của tôi. Trang web cho gcc bao gồm điều này cũng như những người khác. Cũng có một điều tương tự cho các thư viện - -L.
Pryftan

50

Tài liệu của GCC cho biết như sau về sự khác biệt giữa hai:

Cả hai tệp tiêu đề người dùng và hệ thống đều được bao gồm bằng cách sử dụng chỉ thị tiền xử lý ‘#include’. Nó có hai biến thể:

#include <file>

Biến thể này được sử dụng cho các tập tin tiêu đề hệ thống. Nó tìm kiếm một tập tin có tên tập tin trong một danh sách tiêu chuẩn của các thư mục hệ thống. Bạn có thể thêm các thư mục vào danh sách này với -Itùy chọn (xem Invocation ).

#include "file"

Biến thể này được sử dụng cho các tệp tiêu đề của chương trình của riêng bạn. Nó tìm kiếm một tệp có tên tệp đầu tiên trong thư mục chứa tệp hiện tại, sau đó trong các thư mục trích dẫn và sau đó các thư mục tương tự được sử dụng cho <file>. Bạn có thể thêm các thư mục vào danh sách các thư mục trích dẫn với -iquotetùy chọn. Đối số của ‘#include’, cho dù được phân cách bằng dấu ngoặc kép hoặc dấu ngoặc nhọn, hoạt động như một hằng chuỗi trong đó các nhận xét không được nhận dạng và tên macro không được mở rộng. Do đó, #include <x/*y>chỉ định bao gồm một tệp tiêu đề hệ thống có tên x/*y.

Tuy nhiên, nếu dấu gạch chéo ngược xảy ra trong tệp, chúng được coi là ký tự văn bản thông thường, không thoát ký tự. Không có chuỗi thoát ký tự nào phù hợp với hằng chuỗi trong C được xử lý. Do đó, #include "x\n\\y"chỉ định một tên tệp chứa ba dấu gạch chéo ngược. (Một số hệ thống diễn giải '\' như một dấu tách tên đường dẫn. Tất cả các hệ thống này cũng diễn giải ‘/’theo cùng một cách. Nó chỉ dễ sử dụng nhất ‘/’.)

Đó là một lỗi nếu có bất cứ điều gì (ngoài ý kiến) trên dòng sau tên tệp.


46

Nó làm:

"mypath/myfile" is short for ./mypath/myfile

với .hoặc là thư mục của tệp chứa tệp #includenày và / hoặc thư mục làm việc hiện tại của trình biên dịch và / hoặcdefault_include_paths

<mypath/myfile> is short for <defaultincludepaths>/mypath/myfile

Nếu ./là trong <default_include_paths>, thì nó không tạo ra sự khác biệt.

Nếu mypath/myfiletrong một thư mục bao gồm khác, hành vi không được xác định.


12
Không, #include "mypath/myfile"không tương đương với #include "./mypath/myfile". Như câu trả lời của piCookie nói, dấu ngoặc kép cho trình biên dịch tìm kiếm theo cách xác định thực hiện - bao gồm tìm kiếm ở những nơi được chỉ định cho #include <...>. (Trên thực tế, nó có thể tương đương, nhưng chỉ vì, ví dụ, /usr/include/mypath/myfilecó thể được gọi là /usr/include/./mypath/myfile- ít nhất là trên các hệ thống giống Unix.)
Keith Thompson

1
@Keith Thompson: Đúng vậy, tôi đã nghĩ về hộp Linux của mình. Rõ ràng nó có thể khác. Mặc dù trong thực tế, Windows với tư cách là hệ điều hành không phải Posix cũng có phiên dịch / phân tách đường dẫn và ./ cũng tồn tại.
Stefan Steiger

1
tùy chọn dirpath -L sau đó thêm dirpath vào defaultincludepaths, trái ngược với việc mang một ý nghĩa khác cho .(như đã đề cập ở trên). Điều này có kết quả mong đợi là cả hai #include "..."#include <...>tìm kiếm trong dirpath
Protongun

1
Tôi nghĩ rằng câu trả lời này là không chính xác, vì nó ngụ ý rằng các tiêu đề kèm theo dấu ngoặc kép luôn được tìm kiếm trong thư mục làm việc hiện tại. Cơ chế tìm kiếm là cách chi tiết hơn; Câu trả lời này không đầy đủ. Tôi không thêm nhận xét này để phàn nàn hoặc than vãn, nhưng vì hệ thống yêu cầu tôi thêm nhận xét để giải thích lý do tại sao tôi bỏ phiếu trả lời này.
Carlo Wood

39

Các <file>bao gồm kể tiền xử lý để tìm kiếm trong -Idanh bạ và trong các thư mục được xác định trước đầu tiên , sau đó trong thư mục file .c của. Các "file"bao gồm kể tiền xử lý để tìm kiếm thư mục nguồn tập tin của lần đầu tiên , và sau đó trở lại -Ivà được xác định trước. Tất cả các điểm đến được tìm kiếm bằng mọi cách, chỉ có thứ tự tìm kiếm là khác nhau.

Tiêu chuẩn năm 2011 chủ yếu thảo luận về các tệp bao gồm trong "Bao gồm tệp nguồn 16.2".

2 Một chỉ thị tiền xử lý của mẫu

# include <h-char-sequence> new-line

tìm kiếm một chuỗi các vị trí được xác định thực hiện cho một tiêu đề được xác định duy nhất bởi trình tự được chỉ định giữa các dấu phân cách <và> và gây ra sự thay thế của lệnh đó bởi toàn bộ nội dung của tiêu đề. Làm thế nào các địa điểm được chỉ định hoặc tiêu đề được xác định là xác định thực hiện.

3 Một chỉ thị tiền xử lý của mẫu

# include "q-char-sequence" new-line

gây ra sự thay thế của lệnh đó bởi toàn bộ nội dung của tệp nguồn được xác định bởi chuỗi được chỉ định giữa "dấu phân cách. Tệp nguồn có tên được tìm kiếm theo cách xác định thực hiện. Nếu tìm kiếm này không được hỗ trợ hoặc nếu tìm kiếm thất bại , lệnh được xử lý lại như thể nó đọc

# include <h-char-sequence> new-line

với chuỗi chứa giống hệt nhau (bao gồm> ký tự, nếu có) từ lệnh ban đầu.

Lưu ý rằng "xxx"biểu mẫu xuống cấp để <xxx>hình thành nếu không tìm thấy tệp. Phần còn lại được xác định thực hiện.


4
Bạn có thể cung cấp một tham chiếu đến nơi trong tiêu chuẩn C mà -Idoanh nghiệp này được chỉ định không?
juanchopanza

1
Tôi thấy không có tài liệu tham khảo -I.
juanchopanza

2
Đó là phần "xác định thực hiện".

28

#include <file.h>yêu cầu trình biên dịch tìm kiếm tiêu đề trong thư mục "bao gồm" của nó, ví dụ như đối với MinGW, trình biên dịch sẽ tìm kiếm file.htrong C: \ MinGW \ include \ hoặc bất cứ nơi nào trình biên dịch của bạn được cài đặt.

#include "file"báo cho trình biên dịch tìm kiếm thư mục hiện tại (tức là thư mục chứa tệp nguồn) file.

Bạn có thể sử dụng -Icờ cho GCC để nói với nó rằng, khi nó gặp một bao gồm các dấu ngoặc nhọn, nó cũng nên tìm kiếm các tiêu đề trong thư mục sau -I. GCC sẽ coi thư mục sau cờ như thể đó là includesthư mục.

Ví dụ: nếu bạn có một tệp được gọi myheader.htrong thư mục của riêng bạn, bạn có thể nói #include <myheader.h>nếu bạn đã gọi GCC bằng cờ -I .(cho biết rằng tệp đó sẽ tìm kiếm bao gồm trong thư mục hiện tại.)

Không có -Icờ, bạn sẽ phải sử dụng #include "myheader.h"để bao gồm tệp hoặc di chuyển myheader.hđến includethư mục của trình biên dịch.


22

Theo tiêu chuẩn - có, chúng khác nhau:

  • Một chỉ thị tiền xử lý của mẫu

    #include <h-char-sequence> new-line

    tìm kiếm một chuỗi các vị trí được xác định thực hiện cho một tiêu đề được xác định duy nhất bởi trình tự được chỉ định giữa <và các >dấu phân cách và gây ra sự thay thế của lệnh đó bởi toàn bộ nội dung của tiêu đề. Làm thế nào các địa điểm được chỉ định hoặc tiêu đề được xác định là xác định thực hiện.

  • Một chỉ thị tiền xử lý của mẫu

    #include "q-char-sequence" new-line

    gây ra sự thay thế của lệnh đó bởi toàn bộ nội dung của tệp nguồn được xác định bởi trình tự được chỉ định giữa các "dấu phân cách. Tệp nguồn được đặt tên được tìm kiếm theo cách xác định thực hiện. Nếu tìm kiếm này không được hỗ trợ hoặc nếu tìm kiếm thất bại, lệnh sẽ được xử lý lại như thể nó đã đọc

    #include <h-char-sequence> new-line

    với chuỗi chứa giống hệt nhau (bao gồm các >ký tự, nếu có) từ chỉ thị ban đầu.

  • Một chỉ thị tiền xử lý của mẫu

    #include pp-tokens new-line

    (không phù hợp với một trong hai hình thức trước đó) được cho phép. Các mã thông báo tiền xử lý sau includetrong lệnh được xử lý giống như trong văn bản thông thường. (Mỗi mã định danh hiện được xác định là tên macro được thay thế bằng danh sách mã thông báo tiền xử lý thay thế.) Lệnh được tạo sau tất cả các thay thế sẽ khớp với một trong hai dạng trước đó. Phương pháp mà theo đó một chuỗi các tiền xử lý tokens giữa <và một >cặp thẻ tiền xử lý hoặc một cặp "nhân vật được kết hợp thành một tên tiêu đề đơn tiền xử lý mã thông báo là thực hiện xác định.

Định nghĩa:

  • h-char: bất kỳ thành viên nào của bộ ký tự nguồn trừ ký tự dòng mới và >

  • q-char: bất kỳ thành viên nào của bộ ký tự nguồn trừ ký tự dòng mới và "

Lưu ý rằng tiêu chuẩn không cho biết bất kỳ mối quan hệ nào giữa cách cư xử được xác định. Biểu mẫu đầu tiên tìm kiếm theo một cách được xác định theo cách thực hiện và biểu mẫu khác theo cách được xác định theo cách thực hiện (có thể khác). Tiêu chuẩn cũng chỉ định rằng các tệp bao gồm nhất định sẽ có mặt (ví dụ <stdio.h>:).

Chính thức, bạn phải đọc hướng dẫn cho trình biên dịch của mình, tuy nhiên, thông thường (theo truyền thống), #include "..."biểu mẫu tìm kiếm thư mục của tệp #includeđược tìm thấy trước, và sau đó là các thư mục mà #include <...>biểu mẫu tìm kiếm (đường dẫn bao gồm, ví dụ như tiêu đề hệ thống ).


2
Đây hầu như chỉ là văn bản giống như câu trả lời của piCookie từ bảy năm trước.
Kyle Strand

5
@KyleStrand Đó là vì cùng một văn bản là một trích dẫn của phần có liên quan trong tiêu chuẩn - văn bản đó phải giống hệt nhau. Câu trả lời thực tế không phải là cùng một văn bản và có phần khác nhau - trong khi tôi cũng nhận ra rằng nó sẽ được viết trong tài liệu để thực hiện. Tôi cũng lưu ý rằng cũng có một cách truyền thống những cách này được diễn giải (hầu hết hoặc tất cả các trình biên dịch tôi sử dụng đều tôn trọng) .
bầu trời

2
IMO đây là câu trả lời tốt nhất ở đây, bởi vì nó bao gồm cả những gì tiêu chuẩn nói và những gì hầu hết các trình biên dịch thực sự làm.
cắm vào

17

Cảm ơn câu trả lời tuyệt vời, đặc biệt. Adam Stelmaszchot và piCookie, và aib.

Giống như nhiều lập trình viên, tôi đã sử dụng quy ước không chính thức là sử dụng "myApp.hpp"biểu mẫu cho các tệp cụ thể của ứng dụng và <libHeader.hpp>biểu mẫu cho các tệp hệ thống thư viện và trình biên dịch, tức là các tệp được chỉ định trong /IINCLUDEbiến môi trường, trong nhiều năm cho rằng đó là tiêu chuẩn.

Tuy nhiên, tiêu chuẩn C nói rằng thứ tự tìm kiếm là cụ thể, có thể làm cho tính di động trở nên phức tạp. Để làm cho vấn đề tồi tệ hơn, chúng tôi sử dụng kẹt, tự động tìm ra vị trí của các tệp bao gồm. Bạn có thể sử dụng đường dẫn tương đối hoặc tuyệt đối cho các tệp đính kèm của mình. I E

#include "../../MyProgDir/SourceDir1/someFile.hpp"

Các phiên bản cũ hơn của MSVS yêu cầu dấu gạch chéo kép (\\), nhưng hiện tại không bắt buộc. Tôi không biết khi nào nó thay đổi. Chỉ cần sử dụng dấu gạch chéo về phía trước để tương thích với 'nix (Windows sẽ chấp nhận điều đó).

Nếu bạn thực sự lo lắng về nó, hãy sử dụng "./myHeader.h"cho một tệp bao gồm trong cùng thư mục với mã nguồn (dự án rất lớn hiện tại của tôi có một số tên tệp bao gồm trùng lặp - thực sự là một vấn đề quản lý cấu hình).

Đây là lời giải thích MSDN được sao chép ở đây để thuận tiện cho bạn).

Mẫu trích dẫn

Bộ tiền xử lý tìm kiếm các tệp bao gồm theo thứ tự này:

  1. Trong cùng thư mục với tệp chứa câu lệnh #incoide.
  2. Trong các thư mục hiện đang mở bao gồm các tệp, theo thứ tự ngược lại trong đó
    chúng được mở. Việc tìm kiếm bắt đầu trong thư mục của tập tin cha mẹ bao gồm tập tin và
    tiếp tục đi lên thông qua các thư mục của bất kỳ tập tin bao gồm ông bà.
  3. Dọc theo đường dẫn được chỉ định bởi mỗi /Itùy chọn trình biên dịch.
  4. Dọc theo các đường dẫn được chỉ định bởi INCLUDEbiến môi trường.

Hình thức khung góc

Bộ tiền xử lý tìm kiếm các tệp bao gồm theo thứ tự này:

  1. Dọc theo đường dẫn được chỉ định bởi mỗi /Itùy chọn trình biên dịch.
  2. Khi biên dịch xảy ra trên dòng lệnh, dọc theo các đường dẫn được chỉ định bởi INCLUDEbiến môi trường.

16

Ít nhất là đối với phiên bản GCC <= 3.0, biểu mẫu khung góc không tạo ra sự phụ thuộc giữa tệp được bao gồm và tệp bao gồm.

Vì vậy, nếu bạn muốn tạo quy tắc phụ thuộc (sử dụng tùy chọn GCC -M cho ví dụ), bạn phải sử dụng biểu mẫu được trích dẫn cho các tệp nên được bao gồm trong cây phụ thuộc.

(Xem http://gcc.gnu.org/onlinesocs/cpp/Invocation.html )


1
Có - có một số cách khác nhau để tạo ra sự phụ thuộc. Đó là một trong số họ nhưng nó không phải là người duy nhất.
Pryftan

15

Đối với #include ""một trình biên dịch thường tìm kiếm thư mục của tệp chứa bao gồm và sau đó các thư mục khác. Đối với #include <>trình biên dịch không tìm kiếm thư mục của tập tin hiện tại.


1
Không chắc tại sao mọi người không đồng ý.
Maxim Egorushkin

Tôi nghi ngờ đó là vì hầu hết mọi người chỉ biên dịch các tệp trong CWD của họ. Nếu bạn đang ở trong thư mục foo và bạn đang biên dịch foo / unittest / bar.c và nó bao gồm bar.h, thì "bar.h" hoạt động và <bar.h> thì không.

1
@Maxim mọi người không đồng ý vì hành vi bạn mô tả không chuẩn C.
osvein

2
@Spookbuster Đúng, tiêu chuẩn nói cả hai <filename>"filename"tìm kiếm các địa điểm được xác định thực hiện.
Maxim Egorushkin

14

Khi bạn sử dụng #include <filename>, bộ xử lý trước sẽ tìm tệp trong thư mục của tệp tiêu đề C \ C ++ (stdio.h \ cstdio, chuỗi, vector, v.v.). Nhưng, khi bạn sử dụng #include "filename": trước tiên, bộ xử lý trước sẽ tìm tệp trong thư mục hiện tại và nếu không có ở đây - anh ta sẽ tìm nó trong thư mục của tệp tiêu đề C \ C ++.


1
Sau khi một câu trả lời hoàn hảo đã có sẵn trong nhiều năm, tại sao lại gửi một câu hỏi, điều đó hoàn toàn sai? Mặc dù thông thường, lệnh #includenày hoàn toàn không liên quan đến các tệp.
IInspectable

@IInspectable vui lòng giải thích tại sao nó không liên quan đến các tập tin.
Behrooz Karjoo

11

Một #incolee với dấu ngoặc góc sẽ tìm kiếm "danh sách địa điểm phụ thuộc vào việc triển khai" (đây là một cách rất phức tạp để nói "tiêu đề hệ thống") cho tệp được đưa vào.

Một #include với dấu ngoặc kép sẽ chỉ tìm kiếm một tệp (và, "theo cách phụ thuộc vào việc thực hiện", bleh). Điều đó có nghĩa là, trong tiếng Anh thông thường, nó sẽ cố gắng áp dụng đường dẫn / tên tệp mà bạn ném vào nó và sẽ không trả trước một đường dẫn hệ thống hoặc giả mạo nó bằng cách khác.

Ngoài ra, nếu #include "" không thành công, nó sẽ được đọc lại dưới dạng #include <> theo tiêu chuẩn.

Các tài liệu gcc có (biên dịch cụ thể) mô tả mà mặc dù là đặc trưng cho gcc và không phải là tiêu chuẩn, là dễ dàng hơn nhiều để hiểu hơn cuộc nói chuyện luật sư theo phong cách của các tiêu chuẩn ISO.


Tuy nhiên, sử dụng dấu ngoặc nhọn hoặc dấu ngoặc kép không ảnh hưởng đến cách bao gồm các tệp, nó hoàn toàn giống nhau: bộ tiền xử lý về cơ bản tạo ra một tệp nguồn lớn bằng cách sao chép mã từ tệp bao gồm sang tệp nguồn gốc, trước khi đưa ra nó cho trình biên dịch (bộ xử lý trước làm việc khác, như #define sustlation, #if đánh giá, v.v. nhưng việc xử lý #incoide rất dễ dàng)
Loghorn

Còn xung đột thì sao? ví dụ: tôi có zlib.htrong đường dẫn tìm kiếm 'người dùng của tôi và một phiên bản khác tồn tại trong đường dẫn tìm kiếm hệ thống, sau đó có #include <zlib.h>bao gồm phiên bản hệ thống và #include "zlib.h"bao gồm phiên bản của riêng tôi không?
the_mandrill

Aha, đã trả lời câu hỏi của riêng tôi: stackoverflow.com/questions/21593/ từ
the_mandrill

Cảm ơn bạn đã thừa nhận rằng cả (các) tiêu chuẩn quy ước triển khai điển hình đều có liên quan ở đây, thay vì chỉ nói rằng điều đó không thể biết được vì nó không được quy định bởi tiêu chuẩn.
Kyle Strand

10
#include "filename" // User defined header
#include <filename> // Standard library header.

Thí dụ:

Tên tệp ở đây là Seller.h:

#ifndef SELLER_H     // Header guard
#define SELLER_H     // Header guard

#include <string>
#include <iostream>
#include <iomanip>

class Seller
{
    private:
        char name[31];
        double sales_total;

    public:
        Seller();
        Seller(char[], double);
        char*getName();

#endif

Trong triển khai lớp (ví dụ, Seller.cppvà trong các tệp khác sẽ sử dụng tệp Seller.h), tiêu đề được xác định bởi người dùng bây giờ sẽ được đưa vào, như sau:

#include "Seller.h"

10
  • #include <> dành cho các tệp tiêu đề được xác định trước

Nếu tệp tiêu đề được xác định trước thì bạn chỉ cần viết tên tệp tiêu đề trong ngoặc vuông và nó sẽ trông như thế này (giả sử chúng ta có một tên tệp tiêu đề được xác định trước iostream):

#include <iostream>
  • #include " " dành cho các tệp tiêu đề mà lập trình viên định nghĩa

Nếu bạn (lập trình viên) đã viết tệp tiêu đề của riêng bạn thì bạn sẽ viết tên tệp tiêu đề trong dấu ngoặc kép. Vì vậy, giả sử bạn đã viết một tệp tiêu đề được gọi myfile.h, thì đây là một ví dụ về cách bạn sẽ sử dụng lệnh bao gồm để bao gồm tệp đó:

#include "myfile.h"

2
Nó không có gì để làm với các tệp tiêu đề được xác định trước cả. Nó phải làm với các vị trí để tìm kiếm.
C Johnson

9

Nhiều câu trả lời ở đây tập trung vào các đường dẫn trình biên dịch sẽ tìm kiếm để tìm tệp. Mặc dù đây là những gì hầu hết các trình biên dịch làm, một trình biên dịch tuân thủ được phép được lập trình sẵn với các hiệu ứng của các tiêu đề tiêu chuẩn, và coi, #include <list>như một công tắc, và nó hoàn toàn không tồn tại dưới dạng một tệp.

Đây không hoàn toàn là giả thuyết. Có ít nhất một trình biên dịch hoạt động theo cách đó. #include <xxx>Chỉ sử dụng với các tiêu đề tiêu chuẩn.


9
#include <abc.h>

được sử dụng để bao gồm các tệp thư viện tiêu chuẩn. Vì vậy, trình biên dịch sẽ kiểm tra tại các vị trí mà các tiêu đề thư viện chuẩn đang cư trú.

#include "xyz.h"

sẽ báo cho trình biên dịch bao gồm các tệp tiêu đề do người dùng định nghĩa. Vì vậy, trình biên dịch sẽ kiểm tra các tệp tiêu đề này trong thư mục hiện tại hoặc -Icác thư mục được xác định.


7

Trong C ++, bao gồm một tệp theo hai cách:

Cái đầu tiên là #include báo cho bộ xử lý trước tìm tệp ở vị trí mặc định được xác định trước. Vị trí này thường là biến môi trường INCLUDE biểu thị đường dẫn bao gồm các tệp.

Và loại thứ hai là #include "filename" cho biết bộ xử lý trước tìm tệp trong thư mục hiện tại trước, sau đó tìm tệp đó trong các vị trí được xác định trước mà người dùng đã thiết lập.


7

Mẫu 1 - #include <xxx>

Đầu tiên, tìm kiếm sự hiện diện của tệp tiêu đề trong thư mục hiện tại từ đó lệnh được gọi. Nếu không tìm thấy, sau đó nó tìm kiếm trong danh sách cấu hình sẵn của các thư mục hệ thống tiêu chuẩn.

Mẫu 2 - #incolee "xxx"

Điều này tìm kiếm sự hiện diện của tệp tiêu đề trong thư mục hiện tại từ đó lệnh được gọi.


Danh sách thư mục tìm kiếm chính xác phụ thuộc vào hệ thống đích, cách GCC được cấu hình và nơi nó được cài đặt. Bạn có thể tìm thấy danh sách thư mục tìm kiếm của trình biên dịch GCC của mình bằng cách chạy nó với tùy chọn -v.

Bạn có thể thêm các thư mục bổ sung vào đường dẫn tìm kiếm bằng cách sử dụng - I dir , điều này khiến dir được tìm kiếm sau thư mục hiện tại (đối với dạng trích dẫn của lệnh) và trước các thư mục hệ thống tiêu chuẩn.


Về cơ bản, mẫu "xxx" không có gì ngoài tìm kiếm trong thư mục hiện tại; nếu không tìm thấy rơi trở lại mẫu


3
Nếu bạn quyết định trả lời một câu hỏi cũ hơn và có câu trả lời đúng, việc thêm câu trả lời mới vào cuối ngày có thể không giúp bạn nhận được bất kỳ tín dụng nào. Nếu bạn có một số thông tin mới đặc biệt hoặc bạn tin chắc rằng các câu trả lời khác đều sai, bằng mọi cách hãy thêm một câu trả lời mới, nhưng 'một câu trả lời khác' đưa ra thông tin cơ bản tương tự trong một thời gian dài sau khi câu hỏi được hỏi thường thắng ' t kiếm được cho bạn nhiều tín dụng.
Jonathan Leffler

1
@Jonathan Leffler Bạn có thể chỉ cho tôi câu trả lời "được thiết lập tốt" mà bạn cảm thấy ngắn gọn và chính xác như câu trả lời của Darshan không?
Personal_cloud

1
Mô tả của #include "header.h"biểu mẫu không chính xác, @personal_cloud. Tôi coi câu trả lời của piCookieYann Droneaud là phù hợp nhất khi họ xác định thông tin của họ đến từ đâu. Tôi cũng không tìm thấy câu trả lời được bình chọn hàng đầu là hoàn toàn thỏa đáng.
Jonathan Leffler

Tại sao câu trả lời này được hiển thị trên đầu, trong khi hai câu trả lời tiếp theo có hơn 650 phiếu bầu một? Câu trả lời này làm tôi bối rối, vì nó không phù hợp với hành vi mà tôi quan sát được. Điều này có thể là do câu cuối cùng bị hỏng do không thoát khỏi dấu ngoặc góc. Tôi không chắc nó có nghĩa gì.
Sơ khai

6

Các #include <filename>được sử dụng khi một tập tin hệ thống được nhắc đến. Đó là một tệp tiêu đề có thể được tìm thấy tại các vị trí mặc định của hệ thống như /usr/includehoặc /usr/local/include. Đối với các tệp của riêng bạn cần được đưa vào một chương trình khác, bạn phải sử dụng #include "filename"cú pháp.


6

tìm kiếm "<tên tệp>" trong các vị trí thư viện C tiêu chuẩn

trong khi "tên tệp" tìm kiếm trong thư mục hiện tại là tốt.

Lý tưởng nhất là bạn sẽ sử dụng <...> cho các thư viện C tiêu chuẩn và "..." cho các thư viện mà bạn viết và có mặt trong thư mục hiện tại.


4
Những thông tin mới bổ sung câu trả lời này cho những người khác?
Daniel Langr

5

Nguyên tắc chung đơn giản là sử dụng dấu ngoặc nhọn để bao gồm các tệp tiêu đề đi kèm với trình biên dịch. Sử dụng dấu ngoặc kép để bao gồm bất kỳ tệp tiêu đề khác. Hầu hết các trình biên dịch làm theo cách này.

1.9 - Các tệp tiêu đề giải thích chi tiết hơn về các chỉ thị tiền xử lý. Nếu bạn là một lập trình viên mới làm quen, trang đó sẽ giúp bạn hiểu tất cả những điều đó. Tôi đã học được nó từ đây, và tôi đã theo dõi nó tại nơi làm việc.


4
#include <filename>

được sử dụng khi bạn muốn sử dụng tệp tiêu đề của thư viện trình biên dịch hoặc hệ thống C / C ++. Các thư viện này có thể là stdio.h, string.h, math.h, v.v.

#include "path-to-file/filename"

được sử dụng khi bạn muốn sử dụng tệp tiêu đề tùy chỉnh của riêng bạn trong thư mục dự án của bạn hoặc ở một nơi khác.

Để biết thêm thông tin về tiền xử lý và tiêu đề. Đọc C - Tiền xử lý .


3

#include <filename>

  • Bộ tiền xử lý tìm kiếm theo cách phụ thuộc vào việc thực hiện. Nó báo cho trình biên dịch tìm kiếm thư mục nơi các tệp tiêu đề hệ thống được giữ.
  • Phương pháp này thường sử dụng để tìm các tệp tiêu đề tiêu chuẩn.

#include "filename"

  • Điều này báo cho trình biên dịch tìm kiếm các tệp tiêu đề nơi chương trình đang chạy. Nếu thất bại, nó hoạt động như thế #include <filename>và tìm kiếm tệp tiêu đề đó tại nơi lưu trữ tệp tiêu đề hệ thống.
  • Phương pháp này thường được sử dụng để xác định các tệp tiêu đề do người dùng xác định (các tệp tiêu đề được tạo bởi người dùng). Không sử dụng điều này nếu bạn muốn gọi thư viện chuẩn vì mất nhiều thời gian biên dịch hơn #include <filename>.

2

Để xem thứ tự tìm kiếm trên hệ thống của bạn bằng gcc, dựa trên cấu hình hiện tại, bạn có thể thực hiện lệnh sau. Bạn có thể tìm thêm chi tiết về lệnh này tại đây

cpp -v /dev/null -o /dev/null

Apple LLVM phiên bản 10.0.0 (clang-1000.10.44.2)
Mục tiêu: x86_64-apple-darwin18.0.0
Mô hình chủ đề: posix InstalledDir: Library / Developer / CommandLineTools / usr / bin
"/ Thư viện / Nhà phát triển / CommandLineTools / usr / bin / clang" -cc1 -triple x86_64-apple-macosx10.14.0 -Wdeprecated-objc-isa-used -Werror = deprecated-objc-isa-used vô hiệu hóa-llvm-xác minh -discard-value-name -main-file-name null -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-Elim -fno -rict-return -masm-verbose munwind-bảng -target-cpu penryn -dwarf-cột-thông tin -debugger-chỉnh = lldb -target-linker-phiên bản 409.12 -v -resource-dir /L Library / Nhà phát triển / CommLLineTools / usr / lib / 10 isysroot / Thư viện / Nhà phát triển / CommonLineTools / SNKs / MacOSX10,14.sdk -I / usr / local / bao gồm -fdebug-compilation-dir / Users / hogstrom -ferror-giới hạn 19 -fmessage-length -fencode-Extended-block-chữ ký -fobjc-runtime = macosx-10.14.0 -fmax-type-align = 16 -fdiagnostics-show-tùy chọn -fcolor-chẩn đoán -traditable-cpp -o - -xc / dev / null
clang -cc1 phiên bản 10.0.0 (clang-1000.10.44.2) mục tiêu mặc định x86_64-apple-darwin18.0.0 bỏ qua thư mục không tồn tại "/L Library / Nhà phát triển / CommonLineTools / DSKs / MacOSX10,14.sdk / usr thư mục "/ L Library / Nhà phát triển / CommonLineTools / SNKs / MacOSX10.14.sdk / L Library / Frameworks"
#include "..." tìm kiếm bắt đầu tại đây:
#include <...> tìm kiếm bắt đầu tại đây:
/ usr / local / include
/ Thư viện / Nhà phát triển / CommandLineTools / usr / lib / clang / 10.0.0 / bao gồm
/ Thư viện / Nhà phát triển / CommandLineTools / usr / bao gồm / Thư viện / Nhà phát triển /
CommonLineTools
/ SNKs / MacOSX10,14.sdk / usr / inc / CommandLineTools / SDKs / MacOSX10.14.sdk / System / Library / Frameworks (thư mục khung)
Kết thúc danh sách tìm kiếm.


1
#include <file> 

Bao gồm một tập tin trong đó thư mục bao gồm mặc định là.

#include "file" 

Bao gồm một tập tin trong thư mục hiện tại mà nó được biên dịch.


-2

Có hai cách để viết câu lệnh #incoide. Đây là:

#include"filename"
#include<filename>

Ý nghĩa của mỗi hình thức là

#include"mylib.h"

Lệnh này sẽ tìm tệp mylib.htrong thư mục hiện tại cũng như danh sách các thư mục được chỉ định như đã đề cập n đường dẫn tìm kiếm bao gồm có thể đã được thiết lập.

#include<mylib.h>

Lệnh này sẽ tìm tệp mylib.htrong danh sách chỉ định của các thư mục.

Đường dẫn tìm kiếm bao gồm không có gì ngoài một danh sách các thư mục sẽ được tìm kiếm cho tệp được bao gồm. Trình biên dịch C khác nhau cho phép bạn đặt đường dẫn tìm kiếm theo các cách khác nhau.


1
Nếu bạn quyết định trả lời một câu hỏi cũ hơn và có câu trả lời đúng, việc thêm câu trả lời mới vào cuối ngày có thể không giúp bạn nhận được bất kỳ tín dụng nào. Nếu bạn có một số thông tin mới đặc biệt hoặc bạn tin chắc rằng các câu trả lời khác đều sai, bằng mọi cách hãy thêm một câu trả lời mới, nhưng 'một câu trả lời khác' đưa ra thông tin cơ bản tương tự trong một thời gian dài sau khi câu hỏi được hỏi thường thắng ' t kiếm được cho bạn nhiều tín dụng.
Jonathan Leffler
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.