#pragma เป็นส่วนหนึ่งของมาตรฐาน C ++ 11 หรือไม่


140

ตามเนื้อผ้าวิธีมาตรฐานและแบบพกพาเพื่อหลีกเลี่ยงการรวมส่วนหัวหลายรายการใน C ++ คือ / คือการใช้#ifndef - #define - #endifชุดรูปแบบคำสั่ง pre-compiler หรือที่เรียกว่าชุดรูปแบบมหภาคการ์ด (ดูตัวอย่างรหัสด้านล่าง)

#ifndef MY_HEADER_HPP
#define MY_HEADER_HPP
...
#endif

ในการใช้งานมากที่สุด / คอมไพเลอร์ (ดูภาพด้านล่าง) แต่มีอีกทางเลือก "สง่างาม" #pragma onceที่ทำหน้าที่วัตถุประสงค์เช่นเดียวกับโครงการแมโครยามที่เรียกว่า #pragma onceมีข้อดีหลายประการเมื่อเทียบกับชุดรูปแบบการป้องกันมาโครซึ่งรวมถึงรหัสน้อยกว่าการหลีกเลี่ยงการปะทะกันของชื่อและบางครั้งการปรับปรุงความเร็วในการคอมไพล์

ป้อนคำอธิบายรูปภาพที่นี่

ฉันทำการวิจัยบางอย่างฉันรู้ว่าถึงแม้#pragma onceคำสั่งจะได้รับการสนับสนุนจากคอมไพเลอร์ที่รู้จักกันเกือบทั้งหมด แต่ก็มีความขุ่นเคืองว่า#pragma onceคำสั่งนั้นเป็นส่วนหนึ่งของมาตรฐาน C ++ 11 หรือไม่

คำถาม:

  • บางคนสามารถอธิบายได้ว่า#pragma onceคำสั่งนั้นเป็นส่วนหนึ่งของมาตรฐาน C ++ 11 หรือไม่?
  • หากไม่ได้เป็นส่วนหนึ่งของมาตรฐาน C ++ 11 มีแผนใดบ้างในการรวมไว้ในรุ่นที่ใหม่กว่า (เช่น C ++ 14 หรือใหม่กว่า)?
  • มันจะดีถ้ามีใครสามารถอธิบายเพิ่มเติมเกี่ยวกับข้อดี / ข้อเสียในการใช้เทคนิคอย่างใดอย่างหนึ่ง (เช่นแมโคร - การ์ดกับ#pragma once)

9
อนึ่งการห้ามใช้เครื่องหมายขีดล่างคู่สำหรับการ์ดส่วนหัวนั้นเป็นสิ่งต้องห้ามตามมาตรฐานซึ่งสงวนไว้สำหรับการใช้งานสัญลักษณ์ทั้งหมดที่เริ่มต้นด้วยเครื่องหมายขีดล่างคู่ (นอกเหนือจากอื่น ๆ )
Matteo Italia

9
การใช้เครื่องหมายขีดล่างชั้นนำตามด้วยตัวพิมพ์ใหญ่ก็ไม่สามารถใช้ได้เช่นกัน ประการที่สองความขุ่นอยู่ที่ไหน ฉันเพิ่งเห็นคอมไพเลอร์สนับสนุนฉันเห็นไม่มีใครอ้างว่ามันเป็นส่วนหนึ่งของมาตรฐาน?
Yakk - Adam Nevraumont

1
สำหรับสัญลักษณ์ที่สามดูคำถามที่เกี่ยวข้อง: #pragma เคยปลอดภัยหรือไม่ มันมีสถานการณ์ที่การ์ดส่วนหัวทำงาน แต่#pragma onceปกติจะไม่
user1942027

1
เป็นไปได้ที่ซ้ำกันซึ่งตอบคำถามนี้โดยไม่พูดถึง C ++ 11
Yakk - Adam Nevraumont

3
ดีก็ไม่ได้เขียนในเอกสารอย่างเป็นทางการใด ๆ แต่คุณสามารถคิดว่ามันเป็นพฤตินัยมาตรฐาน
Siyuan Ren

คำตอบ:


107

#pragma onceคือไม่ได้มาตรฐาน มันเป็นส่วนขยายที่กว้างขวาง (แต่ไม่ใช่สากล) ซึ่งสามารถใช้ได้

  • หากข้อกังวลเรื่องการพกพาของคุณมี จำกัด และ
  • คุณสามารถมั่นใจได้ว่าไฟล์รวมทั้งหมดของคุณอยู่ในดิสก์ภายในเครื่องเสมอ

มันถูกพิจารณาว่าเป็นมาตรฐาน แต่ถูกปฏิเสธเพราะมันไม่สามารถใช้งานได้อย่างน่าเชื่อถือ (ปัญหาเกิดขึ้นเมื่อคุณมีไฟล์ที่สามารถเข้าถึงได้ผ่านการติดตั้งระยะไกลที่แตกต่างกัน)

มันค่อนข้างง่ายที่จะตรวจสอบให้แน่ใจว่าไม่มีความขัดแย้งด้านการป้องกันในการพัฒนาเดียว สำหรับห้องสมุดซึ่งอาจใช้ในการพัฒนาที่แตกต่างกันวิธีการแก้ปัญหาที่ชัดเจนคือการสร้างตัวอักษรสุ่มจำนวนมากสำหรับการรวมยามเมื่อคุณสร้างมัน (ตัวแก้ไขที่ดีสามารถตั้งค่าให้ทำสิ่งนี้ให้คุณทุกครั้งที่คุณเปิดส่วนหัวใหม่) แต่ถึงแม้จะไม่มีสิ่งนี้ฉันก็ยังไม่พบปัญหาใด ๆ กับความขัดแย้งระหว่างไลบรารี


11
ไม่เพียงแค่เมาท์ระยะไกล ฮาร์ดลิงก์, ซอฟต์ลิงก์, โครงสร้างย่อย (บน Windows) มันอาจยุ่งเหยิงจริงๆ
Tonny

45
ทำไมคอมไพเลอร์ไม่สามารถใช้การตรวจสอบ SHA-1 หรือ MD5 เพื่อระบุไฟล์ได้
Sergey

29
ฉันไม่เห็นจุดที่จะไม่ใส่อะไรลงในมาตรฐานหากคอมไพเลอร์รายใหญ่ทุกรายสนับสนุน มีหลายสิ่งในมาตรฐานที่สนับสนุนน้อยกว่านี้มาก นอกจากนี้ยังดูเหมือนโง่ที่จะบ่นเกี่ยวกับปัญหาขอบเมื่อเรากำลังพูดถึงรวมถึงไฟล์ที่ขัดแย้งชื่อไฟล์เป็นปัญหาใหญ่แล้ว คงจะดีถ้าความต้องการฟีเจอร์ที่ไม่มีปัญหา 100% ถูกนำไปใช้กับแนวคิดของไฟล์ส่วนหัว #included โดยทั่วไป
TED

38
หากรหัสของคุณมีไฟล์บางไฟล์จากตำแหน่งที่แตกต่างกันผ่านลิงก์สัญลักษณ์หรือการเมาท์แบบแปลก ๆ แสดงว่าไม่สามารถพกพาได้ ดังนั้นการโต้เถียงที่pragma onceไม่สามารถพกพาสิ่งที่ไม่ได้พกพาติดตัวไปได้ (และไม่ควรพิจารณาด้วยซ้ำ) นั้นเป็นอีกเรื่องไร้สาระของ C ++ ที่กลับหัวกลับหาง
doc

7
@JoseAntonioDuraOlmos ฉันยอมรับว่าลิงก์สัญลักษณ์เป็นคุณลักษณะของระบบปฏิบัติการซึ่งอยู่นอกขอบเขตของภาษา C ++ ดังนั้นคำถามที่เกิดขึ้นว่าทำไม C ++ comitee ควรพิจารณาบางสิ่งที่อยู่นอกขอบเขตของภาษา? การพยายามรับประกันสิ่งที่ไม่ใช่ความรับผิดชอบของพวกเขานั้นไม่สมเหตุสมผล IMO DOS ได้รับการสนับสนุนเพียง 8 + 3 ตัวอักษรต่อชื่อไฟล์ แต่ก็ไม่มีใครโต้แย้งว่า#includeจะต้องลบออกเพราะคน ๆ หนึ่งสามารถใช้คำสั่งในทางที่ผิดได้ #pragma onceไม่ได้ จำกัด การพกพา แต่อย่างใดโดยที่คุณจะไม่ใช้ประโยชน์จากลิงก์สัญลักษณ์เพื่อหยุดการรวบรวม
doc

32

ส่วน§16.6ของร่างมาตรฐาน ( N3936 ) อธิบาย#pragmaคำสั่งดังนี้:

คำสั่ง preprocessing ของแบบฟอร์ม

# pragma pp-tokensopt new-line

ทำให้การใช้งานมีพฤติกรรมในลักษณะที่กำหนดไว้ในการนำไปใช้ พฤติกรรมนี้อาจทำให้การแปลล้มเหลวหรือทำให้ผู้แปลหรือโปรแกรมผลลัพธ์นั้นทำงานในลักษณะที่ไม่สอดคล้อง pragma ใด ๆ ที่ไม่รู้จักโดยการนำไปใช้จะถูกละเว้น

โดยทั่วไป#pragma onceคืออินสแตนซ์เฉพาะของการนำไปใช้ของ#pragmaคำสั่งและไม่ใช่ไม่ใช่มาตรฐาน ยัง.

มันมักจะได้รับการสนับสนุนอย่างกว้างขวางจาก "ผู้รวบรวมที่สำคัญ" ส่วนใหญ่รวมถึงGCCและClangดังนั้นบางครั้งจึงแนะนำให้หลีกเลี่ยงแผ่นฉนวนกันความร้อน


10
โปรดทราบว่าคุณสามารถทั้งสอง#pragmaและ#defineป้องกันหัว
Yakk - Adam Nevraumont

18
"pragma ใด ๆ ที่ไม่ได้รับการยอมรับโดยการดำเนินการจะถูกละเว้น" หมายความว่าข้อความ: คำเตือน: คำสั่ง pragma ที่ไม่รู้จักไม่สอดคล้องกันใช่หรือไม่
rodrigo

6
"และเป็นวิธีที่แนะนำในการหลีกเลี่ยงแผ่นกันความร้อนหม้อน้ำ" - คำสั่งที่ชัดเจนมาก มันเป็นวิธีที่ไม่ได้มาตรฐานและประโยชน์ของการใช้มันมีน้อยและแทบจะไม่เกี่ยวข้องกับประสบการณ์ของฉันดังนั้นฉันจึงต้อง +1 ของฉันออกไป
อเล็กซ์

19
@Yakk: ถ้ามีคนเขียน#defineheader-guard เขา / เธอไม่มีเหตุผลที่จะเขียน#pragma onceเช่นกัน
Nawaz

5
@Nawaz คอมไพเลอร์สามารถเก็บแคชของทุกไฟล์ (โดยเส้นทาง) ซึ่งได้รับการ#pragma onced และในกรณีที่มันเป็น#included อีกครั้งสามารถข้าม#include(ไม่ได้เปิดไฟล์) gcc ทำเช่นเดียวกันกับ guards header แต่มันบอบบางมาก ๆ วิธี#pragmaหนึ่งทำได้ง่ายส่วนหัวยามยาก
Yakk - Adam Nevraumont
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.