ใช้ไลบรารี C ++ ในรหัส C


103

ฉันมีไลบรารี C ++ ที่มีคลาสต่างๆสำหรับจัดการข้อมูล ฉันมีซอร์สโค้ดสำหรับไลบรารี

ฉันต้องการขยาย C ++ API เพื่อรองรับการเรียกฟังก์ชัน C เพื่อให้สามารถใช้ไลบรารีกับรหัส C และรหัส C ++ ได้ในเวลาเดียวกัน

ฉันใช้โซ่เครื่องมือ GNU (gcc, glibc ฯลฯ ) ดังนั้นการรองรับภาษาและสถาปัตยกรรมจึงไม่ใช่ปัญหา

มีสาเหตุใดบ้างที่ทำให้ไม่สามารถทำได้ในทางเทคนิค ?

มีgotchaอะไรบ้างที่ฉันต้องระวัง?

มีแหล่งข้อมูลโค้ดตัวอย่างและ / หรือเอกสารเกี่ยวกับเรื่องนี้หรือไม่


สิ่งอื่น ๆ ที่ฉันได้ค้นพบ:

  1. ใช้สิ่งต่อไปนี้เพื่อตัดส่วนหัว C ++ ของคุณที่จำเป็นต้องใช้โดยรหัส C

#ifdef __cplusplus
extern "C" {  
#endif  
//  
// Code goes here ...  
//  
#ifdef __cplusplus  
} // extern "C"  
#endif
  1. เก็บอินเทอร์เฟซ C ++ "ของจริง" ไว้ในไฟล์ส่วนหัวที่แยกจากกันซึ่งไม่รวมอยู่ใน C คิดหลักการ PIMPLที่นี่ การใช้#ifndef __cplusplus #errorสิ่งของต่างๆช่วยในการตรวจจับความบ้าคลั่ง
  2. ระวังตัวระบุ C ++ เป็นชื่อในรหัส C
  3. Enums มีขนาดแตกต่างกันระหว่างคอมไพเลอร์ C และ C ++ อาจไม่ใช่ปัญหาหากคุณใช้โซ่เครื่องมือ GNU แต่ยังไงก็ต้องระวัง
  4. สำหรับโครงสร้างให้ทำตามแบบฟอร์มต่อไปนี้เพื่อไม่ให้ C สับสน

    typedef struct X { ... } X
    
  5. จากนั้นใช้พอยน์เตอร์เพื่อส่งผ่านวัตถุ C ++ พวกเขาจะต้องประกาศใน C เป็นโครงสร้าง X โดยที่ X คือวัตถุ C ++

ทั้งหมดนี้ได้รับความอนุเคราะห์จากเพื่อนที่เป็นพ่อมดที่ C ++


5
ค่อนข้างช้า แต่ฉันเขียน howto เล็ก ๆ เกี่ยวกับ C wrapper สำหรับ C ++: teddy.ch/c++_library_in_c
Teddy

คำตอบ:


69

ใช่เป็นไปได้อย่างแน่นอน คุณจะต้องเขียนเลเยอร์อินเทอร์เฟซใน C ++ ที่ประกาศฟังก์ชันด้วยextern "C":

extern "C" int foo(char *bar)
{
    return realFoo(std::string(bar));
}

จากนั้นคุณจะโทรfoo()จากโมดูล C ของคุณซึ่งจะส่งต่อไปยังrealFoo()ฟังก์ชันที่ใช้งานใน C ++

หากคุณต้องการแสดงคลาส C ++ แบบเต็มพร้อมสมาชิกข้อมูลและวิธีการคุณอาจต้องทำงานมากกว่าตัวอย่างฟังก์ชันง่ายๆนี้


ควรextern "C"วางไว้ในการประกาศเท่านั้น (ไม่ใช่ในคำจำกัดความ)? เนื่องจากคุณกล่าวถึง "เลเยอร์ที่ประกาศฟังก์ชัน" แต่โค้ดตัวอย่างของคุณก็เป็นคำจำกัดความเช่นกัน กล่าวอีกนัยหนึ่งเราควรวางไว้ในไฟล์ส่วนหัวหรือไฟล์ต้นฉบับหรือไม่ (หรือทั้งสองอย่าง?)
kyriakosSt

@KyrSt: หากคุณมีไฟล์ส่วนหัวที่มีการประกาศฟังก์ชันอย่างน้อยคุณต้องวางไว้ที่extern "C"นั่น คอมไพเลอร์ของคุณจะบอกคุณว่าคุณต้องใส่นิยามด้วยหรือไม่
Greg Hewgill

23

c ++ คำถามที่พบบ่อย Lite: "วิธีการผสม C และ C ++ รหัส"

gotchas บางส่วนอธิบายไว้ในคำตอบสำหรับคำถามเหล่านี้:

  • [32.8] ฉันจะส่งผ่านวัตถุของคลาส C ++ ไปยัง / จากฟังก์ชัน C ได้อย่างไร
  • [32.9] ฟังก์ชัน C ของฉันสามารถเข้าถึงข้อมูลในออบเจ็กต์ของคลาส C ++ ได้โดยตรงหรือไม่

12

gotcha หลัก: ไม่สามารถจับข้อยกเว้นใน C ได้หากมีความเป็นไปได้ที่จะมีข้อยกเว้นเพิ่มขึ้นในโค้ด C ++ ให้เขียนโค้ด C หรือ Wrapper C ++ อย่างระมัดระวัง ในทางกลับกันข้อยกเว้นเช่นกลไก (เช่น longjump) ในรหัส C (ตามที่พบในภาษาสคริปต์ต่างๆ) ไม่จำเป็นต้องเรียกใช้ตัวทำลายสำหรับวัตถุ C ++ บนสแต็ก


2
จุดที่ดีเกี่ยวกับการโทรแบบ longjump แม้ว่าฉันจะไม่ได้ใช้มันโดยตรง แต่กรอบการทดสอบที่ฉันใช้ก็นำไปใช้ สิ่งที่ควรทราบ ขอบคุณ
Misha M

3

คุณสามารถผสมรหัส C / C ++ หากฟังก์ชัน main () ของคุณอยู่ใน C ++ คุณเพียงแค่ต้องแน่ใจว่าฟังก์ชัน c ของคุณได้รับการประกาศแล้ว

extern "C"

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

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