Tại sao #ifndef và #define được sử dụng trong các tệp tiêu đề C ++?


496

Tôi đã thấy mã như thế này thường khi bắt đầu các tệp tiêu đề:

#ifndef HEADERFILE_H
#define HEADERFILE_H

Và ở cuối tập tin là

#endif

mục đích của việc này là gì?


36
+1 - Tôi cũng có nghi ngờ tương tự, và nhận được nhiều câu trả lời hay hơn ở đây, có thể hữu ích cho khách truy cập trong tương lai: stackoverflow.com/q/3246804/1134940
Abid Rahman K

6
Tôi muốn thêm vào điều này rằng bạn cũng có thể sử dụng #pragma một lần , đó là tất cả những gì bạn phải làm và nó phục vụ cùng một mục đích như ifndef. Để so sánh hai loại này, hãy xem: stackoverflow.com/questions/1143936/ cấp
Kích thước

3
Tốt nhất để đề cập đến những gì a #pragma: nó kích hoạt một tính năng dành riêng cho trình biên dịch. Mặc dù #pragma onceđang rất được hỗ trợ rộng rãi, đó là không chuẩn.
Potatoswatter

3
@Dimension: Tài liệu riêng của GNU ( info cpphoặc xem tại đây ) nói rằng "nó không được công nhận bởi tất cả các bộ tiền xử lý, vì vậy bạn không thể dựa vào nó trong một chương trình di động." Và GNU cpp tối ưu hóa #ifndefthành ngữ phổ biến và di động để nó hiệu quả như #pragma once.
Keith Thompson

3
Một số điều cần xem xét: Không sử dụng tên macro bắt đầu bằng dấu gạch dưới; định danh như vậy được dành riêng để thực hiện. Tinh tế hơn, #ifndef HEADERFILE_Hcó thể vi phạm không gian tên của việc thực hiện tên tiêu đề xảy ra để bắt đầu E; định danh bắt đầu bằng Evà một chữ số hoặc chữ in hoa được dành riêng cho <errno.h>. Tôi đề nghị #ifndef H_HEADERFILE.
Keith Thompson

Câu trả lời:


527

Những người được gọi là #incoide Guard .

Khi tiêu đề được bao gồm, nó sẽ kiểm tra nếu một giá trị duy nhất (trong trường hợp này là HEADERFILE_H ) được xác định. Sau đó, nếu nó không được xác định, nó sẽ xác định nó và tiếp tục với phần còn lại của trang.

Khi mã được đưa vào một lần nữa, lần đầu tiên ifndefthất bại, dẫn đến một tệp trống.

Điều đó ngăn chặn khai báo kép của bất kỳ định danh nào, chẳng hạn như kiểu, enum và biến tĩnh.


1
Koning Baard XIV: VC thậm chí còn có một #pragma oncethứ tương tự :-)
Joey

95
Ngoài ra, nó ngăn chặn các vùi đệ quy ... Hãy tưởng tượng "alice.h" bao gồm "bob.h" và "bob.h" bao gồm "alice.h" và họ không bao gồm các vệ sĩ ...
Kevin Dungs

@Kevin: ý tôi là thế Tôi muốn thao tác một biểu mẫu được mở bằng biểu mẫu để thao tác. Nó có rất nhiều lỗi và tôi không biết phải làm gì. Tôi đã từ bỏ =)

6
@ Ееу: #pragma oncekhông di động; #ifndefthành ngữ phổ biến được khuyến khích.
Keith Thompson

2
@CIsForCookies Đập "quy tắc một định nghĩa" vào công cụ tìm kiếm yêu thích của bạn.
David Schwartz

33
#ifndef <token>
/* code */
#else
/* code to include if the token is defined */
#endif

#ifndefkiểm tra xem mã thông báo đã cho có #definedsớm hơn trong tệp hoặc trong tệp được bao gồm hay không; nếu không, nó bao gồm mã giữa nó và lệnh đóng #elsehoặc, nếu không #elsecó, #endifcâu lệnh. #ifndefthường được sử dụng để làm cho các tệp tiêu đề trở nên bình thường bằng cách xác định mã thông báo sau khi tệp được bao gồm và kiểm tra xem mã thông báo không được đặt ở đầu tệp đó.

#ifndef _INCL_GUARD
#define _INCL_GUARD
#endif

4
Định danh bắt đầu bằng một dấu gạch dưới được bảo lưu; bạn không nên tự xác định chúng. Sử dụng một cái gì đó như #ifndef H_HEADER_NAME.
Keith Thompson

5
Tôi biết đây là một nhận xét cũ, nhưng thực sự hạn chế gạch dưới chỉ áp dụng cho "định danh bên ngoài" - các định danh có thể kết thúc trong bảng ký hiệu của đối tượng được biên dịch, tức là các biến toàn cục và tên hàm. Nó không áp dụng cho tên macro.
Stu

1
Nhận xét của Stu có đúng không? Tôi mới đọc stackoverflow.com/questions/228783/ và bây giờ tôi không chắc lắm.
Sẽ

10

Điều này ngăn chặn việc bao gồm nhiều tệp tiêu đề giống nhau nhiều lần.

#ifndef __COMMON_H__
#define __COMMON_H__
//header file content
#endif

Giả sử bạn đã bao gồm tệp tiêu đề này trong nhiều tệp. Vì vậy, lần đầu tiên __COMMON_H__ không được xác định, nó sẽ được xác định và bao gồm tệp tiêu đề.

Lần tới __COMMON_H__ được xác định, vì vậy nó sẽ không bao gồm lại.


1

Chúng được gọi là ifdef hoặc bao gồm các vệ sĩ.

Nếu viết một chương trình nhỏ có vẻ như không cần thiết, nhưng khi dự án phát triển, bạn có thể cố ý hoặc vô ý bao gồm một tệp nhiều lần, điều này có thể dẫn đến cảnh báo biên dịch như biến đã được khai báo.

#ifndef checks whether HEADERFILE_H is not declared.
#define will declare HEADERFILE_H once #ifndef generates true.
#endif is to know the scope of #ifndef i.e end of #ifndef

Nếu nó không được khai báo có nghĩa là #ifndef tạo true thì chỉ phần giữa #ifndef và #endif được thực thi nếu không. Điều này sẽ ngăn không cho khai báo lại định danh, enums, cấu trúc, v.v ...

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.