ทำไมคอมไพเลอร์ไม่สามารถหลีกเลี่ยงการนำเข้าไฟล์ส่วนหัวได้สองครั้งด้วยตนเอง


13

ใหม่ไปที่ C ++! ดังนั้นฉันจึงอ่านสิ่งนี้: http://www.learncpp.com/cpp-tutorial/110-a-first-look-at-the-preprocessor/

หัวยาม

เนื่องจากไฟล์ส่วนหัวสามารถรวมไฟล์ส่วนหัวอื่น ๆ จึงเป็นไปได้ที่จะสิ้นสุดในสถานการณ์ที่ไฟล์ส่วนหัวรวมหลายครั้ง

ดังนั้นเราจึงกำหนดให้ตัวประมวลผลล่วงหน้าเพื่อหลีกเลี่ยงปัญหานี้ แต่ฉันไม่แน่ใจ - ทำไมคอมไพเลอร์ไม่สามารถทำได้เพียงแค่ ... ไม่นำเข้าสิ่งเดียวกันสองครั้ง

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


ในคอมไพเลอร์ MS มีคำสั่ง#pragma onceใดให้คอมไพเลอร์รวมไฟล์นั้นเพียงครั้งเดียว
CodesInChaos

คำตอบ:


27

พวกเขาสามารถดังที่แสดงโดยภาษาใหม่ที่ทำ

แต่เมื่อมีการตัดสินใจในการออกแบบเมื่อหลายปีก่อน (เมื่อคอมไพเลอร์ C เป็นหลายขั้นตอนอิสระ) และตอนนี้เพื่อรักษาความเข้ากันได้ตัวประมวลผลล่วงหน้าจะต้องดำเนินการในวิธีการบางอย่างเพื่อให้แน่ใจว่า

ในฐานะที่เป็น C ++ สืบทอดวิธีการประมวลผลไฟล์ส่วนหัวจาก C มันรักษาเทคนิคเดียวกัน เราสนับสนุนการตัดสินใจออกแบบเก่า แต่การเปลี่ยนวิธีการทำงานมันอาจเสี่ยงต่อรหัสมากเกินไป ดังนั้นตอนนี้เราต้องสอนผู้ใช้ภาษาใหม่ถึงวิธีการใช้งานยามรวม

มีเคล็ดลับสองสามอย่างที่มีไฟล์ส่วนหัวที่คุณตั้งใจรวมไว้หลาย ๆ ครั้ง (นี่เป็นคุณสมบัติที่มีประโยชน์จริง ๆ ) แม้ว่าหากเราออกแบบกระบวนทัศน์ใหม่ตั้งแต่เริ่มต้นเราสามารถทำให้วิธีนี้เป็นวิธีที่ไม่ใช่ค่าเริ่มต้นในการรวมไฟล์


7

มันจะไม่แสดงออกอย่างชัดเจนเนื่องจากพวกเขาเลือกที่จะรักษาความเข้ากันได้กับ C และทำให้กับ preprocessor มากกว่าระบบบรรจุแบบดั้งเดิม

สิ่งหนึ่งที่อยู่ในใจสำหรับฉันคือฉันมีโครงการที่เป็น API ฉันมีสองไฟล์ส่วนหัวและx86lib.h x86lib_internal.hเนื่องจากภายในมีขนาดใหญ่มากฉันจึงแยกบิต "สาธารณะ" เป็น x86lib.h เพื่อให้ผู้ใช้ไม่ต้องตั้งเวลาเพิ่มเติมสำหรับการรวบรวม

สิ่งนี้นำเสนอปัญหาตลก ๆ เกี่ยวกับการพึ่งพาแม้ว่าดังนั้นฉันจึงจบลงด้วยการไหลที่เป็นเช่นนี้ใน x86lib_internal

  1. ตั้งค่าตัวประมวลผลล่วงหน้าภายใน
  2. รวม x86lib.h (ซึ่งฉลาดในการดำเนินการบางอย่างเมื่อมีการกำหนดภายใน)
  3. ทำบางสิ่งและแนะนำสิ่งที่ใช้ใน x86lib.h
  4. ตั้งค่าการกำหนดตัวประมวลผลล่วงหน้าหลัง
  5. รวม x86lib.h อีกครั้ง (คราวนี้มันจะละเว้นทุกอย่างยกเว้นส่วน AFTER แยกซึ่งขึ้นอยู่กับองค์ประกอบของ x86lib_internal

ฉันจะไม่พูดว่ามันเป็นวิธีที่ดีที่สุดในการทำเรื่องนี้ แต่ก็ประสบความสำเร็จในสิ่งที่ฉันต้องการ


0

ปัญหาอย่างหนึ่งของการยกเว้นส่วนหัวที่ซ้ำกันโดยอัตโนมัติคือมาตรฐาน C ค่อนข้างเงียบในเรื่องของความหมายของชื่อไฟล์ ตัวอย่างเช่นสมมติว่าไฟล์หลักถูกรวบรวมมีคำสั่ง#include "f1.h"และและพบไฟล์สำหรับคำสั่งเหล่านั้นทั้งสองมี#include "f2.h" #include "f3.h"หากf1.hและf2.hอยู่ในไดเรกทอรีที่แตกต่างกัน แต่ถูกค้นพบโดยการค้นหารวมถึงเส้นทางมันจะไม่ชัดเจนว่า#includeคำสั่งภายในไฟล์เหล่านั้นตั้งใจจะโหลดf3.hไฟล์เดียวกันหรือไฟล์อื่น

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

หาก#pragma onceคำสั่งอนุญาตให้ตัวระบุติดตามตามonceความหมายที่คอมไพเลอร์ควรข้ามไฟล์หากตัวระบุตรงกับตัวหนึ่งจาก#pragma onceคำสั่งที่พบก่อนหน้านี้ความหมายจะไม่มีความชัดเจน คอมไพเลอร์ซึ่งสามารถบอกได้ว่า#includeคำสั่งจะโหลด#pragma onceไฟล์ -tagged เดียวกันกับไฟล์ก่อนหน้ามันสามารถประหยัดเวลาได้เล็กน้อยโดยการข้ามไฟล์โดยไม่เปิดอีกครั้ง แต่การตรวจจับดังกล่าวจะไม่สำคัญทางอรรถศาสตร์เนื่องจากไฟล์นั้นจะถูกข้ามหรือไม่ หรือไม่ใช่ชื่อไฟล์ที่ได้รับการยอมรับว่าเป็นการจับคู่ อย่างไรก็ตามฉันไม่ทราบว่าคอมไพเลอร์ตัวใดทำงานในลักษณะนั้น มีคอมไพเลอร์สังเกตว่าไฟล์ตรงกับรูปแบบ#ifndef someIdentifier / #define someIdentifier / #endif [for that ifndef] / nothing followingและการรักษาสิ่งนั้นเทียบเท่ากับข้างต้น#pragma once someIdentifierถ้าsomeIdentifier ยังคงกำหนดเป็นหลักดี

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