เหตุใดจึงใช้ #ifndef และ #define ในไฟล์ส่วนหัว C ++


496

ฉันได้เห็นรหัสเช่นนี้มักจะเริ่มต้นของไฟล์ส่วนหัว:

#ifndef HEADERFILE_H
#define HEADERFILE_H

และในตอนท้ายของไฟล์ก็คือ

#endif

จุดประสงค์ของสิ่งนี้คืออะไร?


36
+1 - ฉันมีข้อสงสัยเหมือนกันและได้รับคำตอบที่ดีกว่านี้ที่นี่อาจเป็นประโยชน์สำหรับผู้เยี่ยมชมในอนาคต: stackoverflow.com/q/3246803/1134940
Abid Rahman K

6
ฉันต้องการเพิ่มในสิ่งนี้ซึ่งคุณสามารถใช้#pragma เพียงครั้งเดียวนั่นคือทั้งหมดที่คุณต้องทำและมันมีจุดประสงค์เดียวกับ ifndef สำหรับการเปรียบเทียบทั้งสองโปรดดูที่: stackoverflow.com/questions/1143936/…
ขนาด

3
ดีที่สุดที่จะพูดถึง#pragmaคืออะไร: มันเปิดใช้งานคุณลักษณะเฉพาะของคอมไพเลอร์ แม้ว่า#pragma onceจะมากได้รับการสนับสนุนอย่างกว้างขวางก็ไม่เป็นมาตรฐาน
Potatoswatter

3
@ ขนาด: เอกสารของ GNU ( info cppหรือดูที่นี่ ) กล่าวว่า "มันไม่ได้รับการยอมรับจากผู้ประมวลผลล่วงหน้าทั้งหมดดังนั้นคุณจึงไม่สามารถเชื่อถือได้ในโปรแกรมพกพา" และ GNU CPP เพิ่มประสิทธิภาพทั่วไปและแบบพกพาสำนวนดังนั้นมันจึงเป็นที่มีประสิทธิภาพ#ifndef #pragma once
Keith Thompson

3
บางสิ่งที่ควรพิจารณา: อย่าใช้ชื่อแมโครที่ขึ้นต้นด้วยเครื่องหมายขีดล่าง ตัวบ่งชี้ดังกล่าวสงวนไว้สำหรับการนำไปใช้งาน เพิ่มเติมอย่างละเอียด#ifndef HEADERFILE_Hสามารถละเมิด namespace การดำเนินงานของส่วนหัวชื่อที่เกิดขึ้นจะเริ่มต้นด้วยE; ตัวบ่งชี้ที่เริ่มต้นด้วยและหลักหรืออักษรตัวพิมพ์ใหญ่จะถูกสงวนไว้เพื่อE ผมขอแนะนำให้<errno.h> #ifndef H_HEADERFILE
Keith Thompson

คำตอบ:


526

เหล่านี้จะเรียกว่ายาม #include

เมื่อรวมส่วนหัวแล้วจะตรวจสอบว่ามีการกำหนดค่าที่ไม่ซ้ำกัน (ในกรณีนี้HEADERFILE_H) หรือไม่ จากนั้นหากไม่ได้กำหนดจะกำหนดและดำเนินการต่อในส่วนที่เหลือของหน้า

เมื่อรหัสถูกรวมอีกครั้งครั้งแรกifndefล้มเหลวส่งผลให้ไฟล์เปล่า

ที่ช่วยป้องกันการประกาศตัวบ่งชี้ใด ๆ เช่นประเภท enums และตัวแปรแบบคงที่


1
Koning Baard XIV: VC ยังมี#pragma once:-) ซึ่งเหมือนกัน
Joey

95
นอกจากนี้ยังช่วยป้องกันการรวมซ้ำซ้อน ... ลองนึกภาพ "alice.h" รวมถึง "bob.h" และ "bob.h" รวมถึง "alice.h" และพวกเขาไม่ได้มีเจ้าหน้าที่ ...
Kevin Dungs

@ เควิน: นั่นคือสิ่งที่ฉันหมายถึง ฉันต้องการจัดการรูปแบบที่เปิดโดยแบบฟอร์มเพื่อจัดการ มันทำให้ฉันมีข้อผิดพลาดมากมายและฉันไม่รู้จะทำอย่างไร ฉันเลิก =)

6
@ Јοеу: #pragma onceไม่พกพา; #ifndefแนะนำให้ใช้สำนวนสามัญ
Keith Thompson

2
@CIsForCookies Punch "one definition rule" เป็นเครื่องมือค้นหาที่คุณชื่นชอบ
David Schwartz

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

#ifndefตรวจสอบว่าโทเค็นที่ให้มา#definedก่อนหน้านี้ในไฟล์หรือในไฟล์ที่รวมอยู่ ถ้าไม่ได้ก็มีรหัสระหว่างมันและปิดที่#elseหรือหากไม่#elseเป็นปัจจุบัน#endifคำสั่ง #ifndefมักจะใช้เพื่อสร้างไฟล์ส่วนหัว idempotent โดยการกำหนดโทเค็นเมื่อไฟล์ถูกรวมและตรวจสอบว่าโทเค็นไม่ได้ตั้งค่าที่ด้านบนของไฟล์นั้น

#ifndef _INCL_GUARD
#define _INCL_GUARD
#endif

4
ตัวระบุที่ขึ้นต้นด้วยขีดล่างจะถูกสงวนไว้ คุณไม่ควรกำหนดด้วยตนเอง #ifndef H_HEADER_NAMEใช้สิ่งที่ต้องการ
Keith Thompson

5
ฉันรู้ว่านี่เป็นความคิดเห็นเก่า แต่จริง ๆ แล้วข้อ จำกัด ขีดล่างใช้เฉพาะกับ "ตัวระบุภายนอก" - ตัวระบุที่สามารถท้ายในตารางสัญลักษณ์ของวัตถุที่รวบรวมเช่นตัวแปรทั่วโลกและชื่อฟังก์ชั่น ไม่ใช้กับชื่อแมโคร
Stu

1
ความคิดเห็นของสตูเป็นจริงหรือไม่? ฉันเพิ่งอ่านstackoverflow.com/questions/228783/…และตอนนี้ฉันก็ไม่แน่ใจ
จะ

9

วิธีนี้จะป้องกันไม่ให้ไฟล์ส่วนหัวเดียวกันซ้ำหลายครั้ง

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

สมมติว่าคุณรวมไฟล์ส่วนหัวนี้ไว้ในหลายไฟล์ ดังนั้นไม่ได้กำหนด __COMMON_H__ เป็นครั้งแรกมันจะถูกกำหนดและรวมไฟล์ส่วนหัวไว้ด้วย

ครั้งต่อไปจะมีการกำหนด __COMMON_H__ ดังนั้นมันจะไม่รวมอีกครั้ง


1

พวกเขาถูกเรียกว่า ifdef หรือรวมถึงยาม

หากเขียนโปรแกรมขนาดเล็กอาจดูเหมือนว่าไม่จำเป็น แต่เมื่อโครงการขยายตัวคุณอาจรวมไฟล์หนึ่งไฟล์โดยเจตนาหรือไม่ตั้งใจหลายครั้งซึ่งอาจส่งผลให้เกิดคำเตือนการคอมไพล์เช่นประกาศตัวแปรแล้ว

#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

หากไม่ได้รับการประกาศซึ่งหมายถึง #ifndef จะสร้างความจริงดังนั้นส่วนที่อยู่ระหว่าง #ifndef และ #endif จะดำเนินการไม่เช่นนั้น สิ่งนี้จะป้องกันไม่ให้ประกาศตัวระบุ enums โครงสร้าง ฯลฯ อีกครั้ง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.