C / C ++ รวมถึงลำดับไฟล์ส่วนหัว


288

คำสั่งใดควรรวมไฟล์ไว้เช่นอะไรคือสาเหตุของการรวมส่วนหัวหนึ่งหน้าไว้ด้วยกัน

ตัวอย่างเช่นไฟล์ระบบ, STL และ Boost ไปก่อนหรือหลังไฟล์รวมในระบบหรือไม่


2
และคำตอบมากมายเหลือเฟือด้านล่างคือเหตุผลที่นักพัฒนา Java ตัดสินใจแยกส่วนหัว :-) บางคำตอบที่ดีจริงๆอย่างไรก็ตามโดยเฉพาะคำเตือนเพื่อให้แน่ใจว่าไฟล์ส่วนหัวของคุณสามารถอยู่คนเดียว
Chris K

37
ฉันชอบคำถามที่มีคะแนน 100+ และน่าสนใจอย่างมากสำหรับบางคนที่ปิดเพราะ "ไม่สร้างสรรค์"
Andreas

ขอแนะนำให้อ่าน: cplusplus.com/forum/articles/10627
Kalsan

3
@mrt ดังนั้นจงเตือนใจชุมชนซุปนาซี: ไม่ว่าคุณจะทำตามกฎที่เข้มงวดมากหรือ "ไม่มีคำตอบ / ความคิดเห็นที่เหมาะสมสำหรับคุณ!" อย่างไรก็ตามหากมีปัญหาเกี่ยวกับการเขียนโปรแกรมนี่เป็นเว็บไซต์แรกที่ไป ..
Imago

คำตอบ:


289

ฉันไม่คิดว่าจะมีคำสั่งแนะนำตราบใดที่มันรวบรวม! สิ่งที่น่ารำคาญก็คือเมื่อส่วนหัวบางส่วนต้องรวมส่วนหัวอื่นก่อน ... นั่นเป็นปัญหาของส่วนหัวเองไม่ใช่ลำดับของการรวม

ความชอบส่วนตัวของฉันคือไปจากท้องถิ่นสู่ระดับโลกแต่ละส่วนย่อยตามลำดับตัวอักษรคือ:

  1. ไฟล์ h ที่สอดคล้องกับไฟล์ cpp นี้ (ถ้ามี)
  2. ส่วนหัวจากองค์ประกอบเดียวกัน
  3. ส่วนหัวจากส่วนประกอบอื่น ๆ
  4. ส่วนหัวของระบบ

เหตุผลของฉันสำหรับ 1. คือควรพิสูจน์ว่าแต่ละส่วนหัว (ซึ่งมี cpp) สามารถเป็น#included โดยไม่มีข้อกำหนดเบื้องต้น (terminus technicus: ส่วนหัวคือ "มีอยู่ในตัวเอง") และที่เหลือก็ดูเหมือนจะไหลจากที่นั่นอย่างมีเหตุผล


16
ค่อนข้างเหมือนกับคุณยกเว้นฉันไปจากทั่วโลกสู่ท้องถิ่นและส่วนหัวที่สัมพันธ์กับไฟล์ต้นฉบับไม่ได้รับการดูแลเป็นพิเศษ
จอนจัง

127
@ จอน: ฉันจะบอกว่ามันค่อนข้างตรงกันข้าม! :-) ฉันจะยืนยันว่าวิธีการของคุณสามารถแนะนำการอ้างอิงที่ซ่อนอยู่พูดได้ว่าถ้า myclass.cpp มี <string> แล้ว <myclass.h> มันไม่มีทางที่จะจับ ณ เวลาสร้างที่ myclass.h นั้นอาจขึ้นอยู่กับสตริง; ดังนั้นหากในภายหลังกับคุณหรือคนอื่นรวมถึง myclass.h แต่ไม่ต้องการสตริงคุณจะได้รับข้อผิดพลาดที่ต้องได้รับการแก้ไขทั้งใน cpp หรือในส่วนหัวของมันเอง แต่ฉันสนใจที่จะทราบว่าเป็นสิ่งที่คนคิดว่าจะทำงานได้ดีขึ้นในระยะยาว ... ทำไมคุณไม่โพสต์คำตอบกับข้อเสนอของคุณและเราจะดูว่าใคร "ชนะ"? ;-)
squelart

3
เฉพาะการสั่งซื้อทั่วไปคือสิ่งที่ฉันใช้ในเวลานี้จากคำแนะนำของ Dave Abrahams และเขาตั้งข้อสังเกตด้วยเหตุผลเดียวกันกับ @squelart ของส่วนหัวที่ขาดหายไปของการส่องสว่างรวมถึงในแหล่งที่มาจากท้องถิ่นถึงทั่วไป กุญแจสำคัญคือการที่คุณมีแนวโน้มที่จะทำผิดพลาดมากกว่าบุคคลที่สามและไลบรารีระบบ
GrafikRobot

7
@PaulJansen นั่นเป็นวิธีปฏิบัติที่ไม่ดีและเป็นเรื่องดีที่จะใช้เทคนิคที่มีแนวโน้มที่จะระเบิดด้วยเพื่อที่ว่าจะสามารถแก้ไขการปฏิบัติที่ไม่ดีได้แทนที่จะซ่อนไว้ FTW ท้องถิ่นสู่ระดับโลก
bames53

10
@ พอลแจนเซนใช่ฉันหมายถึงการเขียนทับพฤติกรรมมาตรฐาน มันอาจเกิดขึ้นโดยบังเอิญเช่นการทำลาย ODR อาจเกิดขึ้นโดยบังเอิญ วิธีการแก้ปัญหาคือไม่ใช้วิธีปฏิบัติที่ซ่อนไว้เมื่อเกิดอุบัติเหตุ แต่ใช้วิธีปฏิบัติที่มีแนวโน้มมากที่สุดที่จะทำให้เกิดเสียงดังที่สุดเท่าที่จะทำได้เพื่อให้สามารถสังเกตและแก้ไขข้อผิดพลาดได้เร็วที่สุด
bames53

106

สิ่งสำคัญที่ต้องจำไว้คือส่วนหัวของคุณไม่ควรขึ้นอยู่กับส่วนหัวอื่น ๆ ที่ถูกรวมไว้ก่อน วิธีหนึ่งในการประกันนี้คือการรวมส่วนหัวของคุณก่อนที่ส่วนหัวอื่น ๆ

"การคิดใน C ++" โดยเฉพาะกล่าวถึงสิ่งนี้โดยอ้างอิงจาก Lakos '"การออกแบบซอฟต์แวร์ C ++ ขนาดใหญ่":

ข้อผิดพลาดในการใช้งานแฝงสามารถหลีกเลี่ยงได้โดยตรวจสอบให้แน่ใจว่าไฟล์. h ของคอมโพเนนต์แยกวิเคราะห์ด้วยตัวเอง - โดยไม่มีการประกาศหรือคำจำกัดความภายนอกที่ระบุ ... รวมถึงไฟล์. h เป็นบรรทัดแรกของไฟล์. c ข้อมูลที่อยู่ในอินเทอร์เฟซทางกายภาพของส่วนประกอบหายไปจากไฟล์. h (หรือหากมีอยู่คุณจะพบข้อมูลนั้นทันทีที่คุณพยายามรวบรวมไฟล์. c)

กล่าวคือรวมไว้ในลำดับต่อไปนี้:

  1. ส่วนหัวต้นแบบ / ส่วนต่อประสานสำหรับการนำไปใช้งานนี้ (เช่นไฟล์. h / .hh ที่สอดคล้องกับไฟล์. cpp / .cc นี้)
  2. ส่วนหัวอื่น ๆ จากโครงการเดียวกันตามต้องการ
  3. ส่วนหัวจากไลบรารีอื่นที่ไม่ได้มาตรฐานและไม่ใช่ระบบ (ตัวอย่างเช่น Qt, Eigen ฯลฯ )
  4. ส่วนหัวจากไลบรารี "เกือบมาตรฐาน" อื่น ๆ (ตัวอย่างเช่น Boost)
  5. ส่วนหัว C ++ มาตรฐาน (ตัวอย่างเช่น iostream, functional, ฯลฯ )
  6. ส่วนหัวมาตรฐาน C (เช่น cstdint, dirent.h เป็นต้น)

หากส่วนหัวใดมีปัญหาในการรวมอยู่ในคำสั่งซื้อนี้ให้แก้ไข (ถ้าเป็นของคุณ) หรือไม่ใช้ ห้องสมุด Boycott ที่ไม่เขียนหัวเรื่องที่สะอาด

คู่มือสไตล์ C ++ ของ Google ให้เหตุผลว่าเกือบจะตรงกันข้ามโดยไม่มีเหตุผลใด ๆ เลย โดยส่วนตัวแล้วผมชอบวิธีการของลอส


13
ณ ตอนนี้คู่มือสไตล์ Google C ++แนะนำให้รวมไฟล์ส่วนหัวที่เกี่ยวข้องก่อนตามคำแนะนำของ Lakos
Filip Bártek

คุณไม่ได้รับอะไรมากไปกว่าหัวข้อแรกที่เกี่ยวข้องเพราะเมื่อคุณเริ่มรวมส่วนหัวในโครงการของคุณคุณจะได้รับการพึ่งพาจากระบบจำนวนมาก
คา

@Micah - ส่วนหัวในโครงการที่ดึงใน "การพึ่งพาระบบจำนวนมาก" คือการออกแบบที่ไม่ดีอย่างแม่นยำสิ่งที่เรากำลังพยายามหลีกเลี่ยงที่นี่ ประเด็นคือเพื่อหลีกเลี่ยงทั้งการรวมที่ไม่จำเป็นและการพึ่งพาที่ไม่ได้รับการแก้ไข ส่วนหัวทั้งหมดควรสามารถรวมได้โดยไม่รวมส่วนหัวอื่นก่อน ในกรณีที่ส่วนหัวในโครงการต้องการการพึ่งพาระบบดังนั้นไม่ว่าคุณจะ (และไม่ควร) รวมการพึ่งพาระบบไว้หลังจากนั้นเว้นแต่โค้ดในเครื่องของไฟล์นั้นจะใช้สิ่งต่าง ๆ จากระบบนั้น คุณไม่สามารถและไม่ควรพึ่งพาส่วนหัว (รวมถึงของคุณ) เพื่อรวมระบบที่คุณใช้
Nathan Paul Simons

49

ฉันปฏิบัติตามกฎง่ายๆสองข้อที่หลีกเลี่ยงปัญหาส่วนใหญ่:

  1. ส่วนหัวทั้งหมด (และแน่นอนใด ๆไฟล์ที่มา) ควรจะรวมถึงสิ่งที่พวกเขาต้องการ พวกเขาไม่ควรพึ่งพาผู้ใช้รวมถึงสิ่งต่าง ๆ
  2. ในฐานะที่เป็นส่วนเสริมส่วนหัวทั้งหมดควรมีตัวป้องกันเพื่อไม่ให้รวมหลาย ๆ ครั้งโดยการใช้กฎที่ 1 ที่มีความทะเยอทะยานมากเกินไป

ฉันทำตามแนวทางของ:

  1. รวมส่วนหัวของระบบก่อน (stdio.h ฯลฯ ) ด้วยเส้นแบ่ง
  2. จัดกลุ่มตามหลักเหตุผล

ในคำอื่น ๆ :

#include <stdio.h>
#include <string.h>

#include "btree.h"
#include "collect_hash.h"
#include "collect_arraylist.h"
#include "globals.h"

ถึงแม้ว่าการเป็นแนวทางเป็นเรื่องส่วนตัว ในทางกลับกันฉันบังคับใช้อย่างเหนียวแน่นถึงแม้จะให้ไฟล์ส่วนหัว 'wrapper' พร้อมด้วยยามรวมและจัดกลุ่มรวมหากนักพัฒนาบุคคลที่สามที่น่ารังเกียจบางคนไม่สมัครเป็นสมาชิกวิสัยทัศน์ของฉัน :-)


6
+1 "ส่วนหัวทั้งหมด (และแน่นอนไฟล์ต้นฉบับ) ควรรวมถึงสิ่งที่พวกเขาต้องการพวกเขาไม่ควรพึ่งพาผู้ใช้รวมถึงสิ่งต่าง ๆ " ยังมีคนจำนวนมากที่พึ่งพาพฤติกรรมการรวมโดยปริยายเช่นนี้ด้วย NULL และไม่รวม <cstddef> มันน่ารำคาญมากเมื่อพยายามพอร์ตรหัสนี้และรับข้อผิดพลาดในการรวบรวมใน NULL (เหตุผลหนึ่งที่ฉันเพิ่งใช้ 0 ตอนนี้)
stinky472

20
ทำไมคุณถึงรวมส่วนหัวของระบบก่อน มันจะดีกว่าทำไมอีกรอบเพราะกฎข้อแรก
jhasse

หากคุณใช้แมโครทดสอบคุณลักษณะครั้งแรกของคุณอาจไม่ควรเป็นส่วนหัวของไลบรารีมาตรฐาน ดังนั้นสำหรับคนทั่วไปฉันพูดได้ว่านโยบาย "ท้องถิ่นลำดับแรกระดับโลกในภายหลัง" นั้นดีที่สุด
hmijail mourns ลาออก

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

22

เพื่อเพิ่มอิฐของฉันเองบนผนัง

  1. แต่ละส่วนหัวจะต้องมีความพอเพียงซึ่งสามารถทดสอบได้หากรวมไว้อย่างน้อยหนึ่งครั้ง
  2. หนึ่งไม่ควรปรับเปลี่ยนความหมายของส่วนหัวของบุคคลที่สามโดยไม่เหมาะสมด้วยการแนะนำสัญลักษณ์ (แมโครประเภท ฯลฯ )

ดังนั้นฉันมักจะไปเช่นนี้:

// myproject/src/example.cpp
#include "myproject/example.h"

#include <algorithm>
#include <set>
#include <vector>

#include <3rdparty/foo.h>
#include <3rdparty/bar.h>

#include "myproject/another.h"
#include "myproject/specific/bla.h"

#include "detail/impl.h"

แต่ละกลุ่มคั่นด้วยบรรทัดว่างจากกลุ่มถัดไป:

  • ส่วนหัวที่สอดคล้องกับไฟล์ cpp นี้ก่อน (ตรวจสอบสติ)
  • ส่วนหัวของระบบ
  • ส่วนหัวของบุคคลที่สามซึ่งจัดระเบียบตามคำสั่งการพึ่งพา
  • ส่วนหัวของโครงการ
  • ส่วนหัวของโครงการส่วนตัว

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


2
เพื่อไม่ให้ไฟล์ส่วนหัวอื่น ๆ ไม่ได้รับผลกระทบ ทั้งสองสิ่งที่ส่วนหัวของระบบเหล่านั้นกำหนด (ทั้ง X รวมและ Windows รวมถึงไม่ดีเกี่ยวกับ#defineที่ทำให้รหัสอื่นสับสน) และเพื่อป้องกันการพึ่งพาโดยนัย ตัวอย่างเช่นหากไฟล์ส่วนหัวของรหัสฐานของเราfoo.hขึ้นอยู่กับ<map>ทุกที่ แต่มันถูกใช้ใน.ccไฟล์<map>เกิดขึ้นเพื่อรวมไว้แล้วเราอาจจะไม่สังเกตเห็น จนกว่าจะมีคนพยายามรวมfoo.hโดยไม่รวม<map>ก่อน แล้วพวกเขาก็จะรำคาญ

@ 0A0D: ปัญหาที่สองไม่ใช่ปัญหาตามลำดับที่นี่เพราะแต่ละอย่าง.hมีอย่างน้อยหนึ่ง.cppที่รวมไว้ก่อน (แน่นอนในรหัสส่วนตัวของฉันการทดสอบหน่วยที่เกี่ยวข้องรวมไว้ก่อน ) เกี่ยวกับการไม่ได้รับอิทธิพลหากส่วนใดส่วนหนึ่งรวมถึงส่วนหัว<map>ทั้งหมดที่รวมอยู่ในภายหลังนั้นจะได้รับอิทธิพลอยู่แล้วดังนั้นจึงดูเหมือนว่าการต่อสู้จะแพ้ไป
Matthieu M.

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

@MatthieuM Header corresponding to this cpp file first (sanity check)ฉันอยากจะรู้ว่าเหตุผลที่อยู่เบื้องหลังจุดหนึ่งคือ มีสิ่งใดเป็นพิเศษหรือไม่หาก#include "myproject/example.h"ถูกย้ายไปยังจุดสิ้นสุดของการรวมทั้งหมด?
MNS

1
@MNS: ส่วนหัวควรเป็นแบบอิสระนั่นคือมันไม่ควรจะต้องรวมส่วนหัวอื่น ๆ ไว้ก่อน มันเป็นความรับผิดชอบของคุณในฐานะนักเขียนของส่วนหัวเพื่อให้แน่ใจในเรื่องนี้และวิธีที่ดีที่สุดในการทำเช่นนั้นคือการมีไฟล์ต้นฉบับหนึ่งไฟล์ซึ่งรวมส่วนหัวนี้ไว้ก่อน การใช้ไฟล์ต้นฉบับที่สอดคล้องกับไฟล์ส่วนหัวนั้นเป็นเรื่องง่ายอีกทางเลือกที่ดีคือการใช้ไฟล์ทดสอบหน่วยที่สอดคล้องกับไฟล์ส่วนหัว แต่เป็นสากลน้อยกว่า (อาจไม่มีการทดสอบหน่วย)
Matthieu M.

16

ฉันแนะนำ:

  1. ส่วนหัวสำหรับโมดูล. cc ที่คุณกำลังสร้าง (ช่วยให้แน่ใจว่าแต่ละส่วนหัวในโครงการของคุณไม่มีการอ้างอิงโดยนัยสำหรับส่วนหัวอื่น ๆ ในโครงการของคุณ)
  2. ไฟล์ระบบ C
  3. ไฟล์ระบบ C ++
  4. Platform / OS / ไฟล์ส่วนหัวอื่น ๆ (เช่น win32, gtk, openGL)
  5. ไฟล์ส่วนหัวอื่น ๆ จากโครงการของคุณ

และแน่นอนเรียงตามตัวอักษรภายในแต่ละส่วนหากเป็นไปได้

ใช้การประกาศไปข้างหน้าเสมอเพื่อหลีกเลี่ยงการที่ไม่จำเป็น#includeในไฟล์ส่วนหัวของคุณ


+1 แต่ทำไมต้องเรียงตามตัวอักษร ดูเหมือนว่าบางสิ่งที่อาจทำให้คุณรู้สึกดีขึ้น แต่ไม่มีประโยชน์ในทางปฏิบัติ
Ben

9
เรียงตามตัวอักษรเป็นคำสั่งโดยพลการ แต่เป็นวิธีที่ง่าย คุณไม่ต้องทำตามตัวอักษร แต่คุณต้องเลือกคำสั่งบางอย่างเพื่อให้ทุกคนทำอย่างสม่ำเสมอ ฉันพบว่ามันช่วยหลีกเลี่ยงการซ้ำซ้อนและทำให้การผสานง่ายขึ้น และถ้าคุณใช้ข้อความประเสริฐ F5 จะสั่งให้คุณ
i_am_jorf

14

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

#include <set>
#include <vector>
#include <algorithm>
#include <functional>

ฉันคิดว่าเป็นความคิดที่ดีที่จะรวมส่วนหัวของคุณไว้ต่อหน้าคนอื่นเพื่อหลีกเลี่ยงความอับอายของการพึ่งพาคำสั่งซื้อ


3
ฉันชอบเรียงลำดับส่วนหัวของฉันโดยใช้คีย์ที่ประกอบด้วยตัวอักษรตัวที่สองที่สามและตัวที่หนึ่งตามลำดับ :-) ดังนั้นเวกเตอร์ชุดอัลกอริทึมการทำงานสำหรับตัวอย่างของคุณ
paxdiablo

@paxdiablo ขอบคุณสำหรับเคล็ดลับ ฉันกำลังพิจารณาที่จะใช้มัน แต่ฉันกังวลว่ามันอาจจบลงด้วยการทิ้งกองชื่อไฟล์ที่ไม่เสถียรและน่าจะพลิกคว่ำ ใครจะรู้ว่าสิ่งที่อาจจะรวมถึงหากเกิดเหตุการณ์นี้ - windows.hบางทีแม้กระทั่ง
clstrfsck

40
เรียงตามความยาว ? บ้า!
James McNellis

1
+1 สำหรับครั้งแรก มันสมเหตุสมผลแล้วถ้าคุณต้องการค้นหาส่วนหัวภายในไฟล์ด้วยตาของคุณมันจะดีกว่าตัวอักษรมาก
Kugel

6

สิ่งนี้ไม่ใช่เรื่องส่วนตัว ตรวจสอบให้แน่ใจว่าส่วนหัวของคุณไม่พึ่งพาการ#includeเรียงตามลำดับ คุณสามารถมั่นใจได้ว่าไม่สำคัญว่าคุณจะมีส่วนหัวลำดับ STL หรือ Boost


1
ฉันสันนิษฐานว่าไม่มีการพึ่งพาโดยปริยาย
Anycorn

ใช่ แต่คอมไพเลอร์ไม่สามารถตั้งสมมติฐานนี้ได้ดังนั้น #include <A>, <B> จะไม่เหมือนกับ #include <B>, <A> จนกว่าพวกเขาจะถูกรวบรวม
มิคาอิล

4

ก่อนอื่นให้รวมส่วนหัวที่เกี่ยวข้องกับ. cpp ... ในคำอื่น ๆsource1.cppควรรวมไว้source1.hก่อนรวมสิ่งอื่นใด ข้อยกเว้นเดียวที่ฉันคิดได้คือเมื่อใช้ MSVC กับส่วนหัวที่รวบรวมไว้ล่วงหน้าซึ่งในกรณีนี้คุณจะถูกบังคับให้รวมstdafx.hก่อนสิ่งอื่นใด

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

ตัวอย่าง:

source1.h

class Class1 {
    Class2 c2;    // a dependency which has not been forward declared
};

source1.cpp

#include "source1.h"    // now compiler will alert you saying that Class2 is undefined
                    // so you can forward declare Class2 within source1.h
...

ผู้ใช้ MSVC:ฉันขอแนะนำอย่างยิ่งให้ใช้ส่วนหัวที่รวบรวมไว้ล่วงหน้า ดังนั้นย้ายทั้งหมด#includeสั่งสำหรับส่วนหัวมาตรฐาน (และส่วนหัวอื่น ๆ ที่ไม่เคยไปมีการเปลี่ยนแปลง) stdafx.hเพื่อ


2

รวมจากส่วนที่เฉพาะเจาะจงมากที่สุดถึงน้อยที่สุดเริ่มต้นด้วย. hpp ที่เกี่ยวข้องสำหรับ. cpp หากมีอยู่จริง ด้วยวิธีนี้การอ้างอิงที่ซ่อนอยู่ใด ๆ ในไฟล์ส่วนหัวที่ไม่เพียงพอจะถูกเปิดเผย

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


1

มันเป็นคำถามที่ยากในโลก C / C ++ ที่มีองค์ประกอบมากมายเกินกว่ามาตรฐาน

ฉันคิดว่าคำสั่งไฟล์ส่วนหัวไม่ใช่ปัญหาร้ายแรงตราบใดที่มันคอมไพล์เช่น squelart กล่าว

ความคิดของฉันคือ: หากไม่มีความขัดแย้งของสัญลักษณ์ในส่วนหัวทั้งหมดคำสั่งใด ๆ ก็โอเคและปัญหาการพึ่งพาส่วนหัวสามารถแก้ไขได้ในภายหลังโดยการเพิ่ม #include บรรทัดลงในข้อบกพร่อง. h

ความยุ่งยากที่แท้จริงเกิดขึ้นเมื่อส่วนหัวบางส่วนเปลี่ยนการกระทำของมัน (โดยการตรวจสอบ #if เงื่อนไข) ตามสิ่งที่ส่วนหัวอยู่ด้านบน

ตัวอย่างเช่นใน stddef.h ใน VS2005 มี:

#ifdef  _WIN64
#define offsetof(s,m)   (size_t)( (ptrdiff_t)&(((s *)0)->m) )
#else
#define offsetof(s,m)   (size_t)&(((s *)0)->m)
#endif

ตอนนี้ปัญหา: ถ้าฉันมีส่วนหัวที่กำหนดเอง ("custom.h") ที่จำเป็นต้องใช้กับคอมไพเลอร์จำนวนมากรวมถึงบางส่วนที่เก่ากว่าที่ไม่ได้ให้offsetofไว้ในส่วนหัวของระบบฉันควรเขียนในส่วนหัวของฉัน:

#ifndef offsetof
#define offsetof(s,m)   (size_t)&(((s *)0)->m)
#endif

และให้แน่ใจว่าได้แจ้งให้ผู้ใช้ทราบ#include "custom.h" หลังจากส่วนหัวของระบบทั้งหมดมิฉะนั้นบรรทัดoffsetofใน stddef.h จะยืนยันข้อผิดพลาดในการกำหนดแมโครซ้ำ

เราสวดอ้อนวอนไม่ให้พบกรณีเช่นนี้ในอาชีพของเราอีกต่อไป

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