รวมไฟล์ซอร์ส C หนึ่งไฟล์ไว้ในไฟล์อื่นหรือไม่


112

มันตกลง (หรือแม้กระทั่งแนะนำ / วิธีปฏิบัติที่ดี) ไปไฟล์อีกไฟล์?#include.c.c


4
ฉันใช้เสรีภาพในการแก้ไขคำถามและใช้แท็กที่มีประโยชน์ด้วย แท็กบางแท็กของฉันอาจมีอคติฮิฮิ
ผ่อนคลาย

คำตอบ:


114

ใช้อย่างถูกต้องนี่อาจเป็นเทคนิคที่มีประโยชน์

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

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

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

หากคุณใส่ทุกอย่างลงในโมดูลแหล่งที่มา C คุณจะได้รับ -

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

  • การซ่อนข้อมูลและฟังก์ชันระดับลิงก์

  • การหลีกเลี่ยงมลพิษของเนมสเปซและข้อพิสูจน์ - คุณสามารถใช้ชื่อที่ดูเทอะทะน้อยลง

  • รวบรวมและเชื่อมโยงได้เร็วขึ้น

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

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

  • ใส่อินเทอร์เฟซสาธารณะในไฟล์ส่วนหัวแยกต่างหาก - คุณควรทำสิ่งนี้ต่อไป

  • มีไฟล์. c หลักหนึ่งไฟล์ที่มีไฟล์. c ในเครือทั้งหมด ซึ่งอาจรวมถึงรหัสสำหรับอินเทอร์เฟซสาธารณะ

  • ใช้คอมไพเลอร์การ์ดเพื่อให้แน่ใจว่าส่วนหัวส่วนตัวและโมดูลซอร์สไม่รวมอยู่ในยูนิตคอมไพเลอร์ภายนอก

  • ข้อมูลและฟังก์ชันส่วนตัวทั้งหมดควรได้รับการประกาศแบบคงที่

  • รักษาความแตกต่างของแนวคิดระหว่างไฟล์. c และ. h สิ่งนี้ใช้ประโยชน์จากอนุสัญญาที่มีอยู่ ความแตกต่างคือคุณจะมีการประกาศแบบคงที่จำนวนมากในส่วนหัวของคุณ

  • หาก toolchain ของคุณไม่ได้กำหนดเหตุผลที่จะไม่ให้ตั้งชื่อไฟล์การนำไปใช้งานส่วนตัวเป็น. c และ. h หากคุณใช้รวมยามสิ่งเหล่านี้จะไม่สร้างรหัสและไม่มีชื่อใหม่ (คุณอาจจบลงด้วยบางส่วนที่ว่างเปล่าระหว่างการเชื่อมโยง) ข้อได้เปรียบอย่างมากคือเครื่องมืออื่น ๆ (เช่น IDE) จะจัดการไฟล์เหล่านี้อย่างเหมาะสม


1
+1 นี่ยังคงเป็นความจริงในขณะที่คอมไพเลอร์ที่ดีกว่าจะทำให้วิธีนี้ล้าสมัยไปตามกาลเวลา GCC 4.5 พร้อมด้วยการเพิ่มประสิทธิภาพเวลาเชื่อมโยงเป็นก้าวสำคัญในหนทาง
u0b34a0f6ae

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

ในการพัฒนาแบบฝังสำหรับ C51 การใช้ไฟล์ C ภายนอกและหลายไฟล์ไม่ได้ทำให้เกิดอะไรขึ้นนอกจากความปวดหัว ฉันเปลี่ยนไปใช้ไฟล์ C หนึ่งไฟล์รวมไฟล์อื่น ๆ ทั้งหมดเพื่อเรียกเวลาของฉันกลับคืนมา
mahesh

สำหรับบันทึก: GCC สนับสนุนการเพิ่มประสิทธิภาพในหน่วยการแปลที่แตกต่างกันให้ดูที่หัวข้อ SO นี้และ GCC คู่มือส่วนที่เกี่ยวกับการเพิ่มประสิทธิภาพการเชื่อมโยงเวลา
Twonky

60

ไหวมั้ย? ใช่มันจะรวบรวม

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


14
นอกจากนี้ที่น่าสังเกตว่าแม้ว่าจะคอมไพล์ แต่ก็อาจไม่เชื่อมโยงหากไฟล์ #included .c ถูกคอมไพล์ด้วยและไฟล์อ็อบเจ็กต์ทั้งสองเชื่อมโยงเข้าด้วยกันคุณอาจลงเอยด้วยสัญลักษณ์ที่กำหนดแบบทวีคูณ
Nick Meyer

1
คำถามเล็ก ๆ ฉันมีไฟล์ส่วนหัวที่ประกาศวิธีการ struct + และไฟล์. c ที่เกี่ยวข้องเพื่อกำหนด หากเมธอดนั้นใช้โครงสร้างเป็นพารามิเตอร์ฉันจะหลีกเลี่ยงการรวมไฟล์. c ในไฟล์. c อื่นที่กำหนดเมธอดหลักได้อย่างไร
stdout

12

ไม่

ขึ้นอยู่กับสภาพแวดล้อมการสร้างของคุณ (คุณไม่ได้ระบุ) คุณอาจพบว่ามันทำงานได้ตรงตามที่คุณต้องการ

อย่างไรก็ตามมีหลายสภาพแวดล้อม (ทั้ง IDE และ Makefiles ที่สร้างขึ้นด้วยมือจำนวนมาก) ที่คาดว่าจะคอมไพล์ * .c - หากเป็นเช่นนั้นคุณอาจพบข้อผิดพลาดของตัวเชื่อมโยงเนื่องจากสัญลักษณ์ซ้ำกัน

ตามกฎแล้วควรหลีกเลี่ยงการปฏิบัตินี้

หากคุณต้อง #include ซอร์สอย่างแน่นอน (และโดยทั่วไปควรหลีกเลี่ยง) ให้ใช้คำต่อท้ายไฟล์อื่นสำหรับไฟล์


9

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

การรวมไฟล์. c ทำให้เราสามารถเข้าถึงฟันเฟืองในเครื่องที่เราสนใจในการทดสอบ


6

คุณสามารถใช้คอมไพเลอร์ gcc ใน linux เพื่อลิงก์ไฟล์ c สองไฟล์ในเอาต์พุตเดียว สมมติว่าคุณมีไฟล์ c สองไฟล์ไฟล์หนึ่งคือ 'main.c' และอีกไฟล์คือ 'support.c' ดังนั้นคำสั่งในการเชื่อมโยงสองสิ่งนี้คือ

gcc main.c support.c -o main.out

โดยสองไฟล์นี้จะเชื่อมโยงกับ main.out เอาต์พุตเดียวในการรันเอาต์พุตคำสั่งจะเป็น

./main.out

หากคุณกำลังใช้ฟังก์ชันใน main.c ซึ่งประกาศไว้ในไฟล์ support.c คุณควรประกาศไว้ใน main โดยใช้คลาสพื้นที่เก็บข้อมูลภายนอก


5

นามสกุลของไฟล์ไม่สำคัญกับคอมไพเลอร์ C ส่วนใหญ่ดังนั้นมันจึงทำงานได้

อย่างไรก็ตามขึ้นอยู่กับการตั้งค่า makefile หรือโปรเจ็กต์ของคุณไฟล์ c ที่รวมอยู่อาจสร้างไฟล์อ็อบเจ็กต์แยกต่างหาก เมื่อเชื่อมโยงที่อาจนำไปสู่สัญลักษณ์ที่กำหนดไว้สองครั้ง


3

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

แก้ไข: ขออภัยฉันให้คำตอบแทนที่จะตอบกลับคำตอบอื่น ๆ :(


1

ภาษาซีไม่ได้ห้าม #include ประเภทนั้น แต่หน่วยการแปลผลลัพธ์ยังคงต้องเป็น C ที่ถูกต้อง

ฉันไม่รู้ว่าคุณกำลังใช้โปรแกรมอะไรกับไฟล์. prj หากคุณกำลังใช้บางอย่างเช่น "make" หรือ Visual Studio หรืออะไรก็ตามเพียงตรวจสอบให้แน่ใจว่าคุณได้ตั้งค่ารายการไฟล์ที่จะรวบรวมโดยไม่มีไฟล์ที่ไม่สามารถคอมไพล์แยกกันได้


0

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

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


-6

คุณควรเพิ่มส่วนหัวแบบนี้

#include <another.c>

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

ฉันใช้สิ่งนี้ใน codevison AVR สำหรับตัวควบคุมไมโคร ATMEGA และทำงานได้จริง แต่ไม่ทำงานในไฟล์ภาษา C ปกติ

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