ฟังก์ชันอินไลน์

ในภาษาการเขียนโปรแกรมCและC++ ฟังก์ชันอินไลน์คือฟังก์ชันที่มีคุณสมบัติพร้อมคีย์เวิร์ดสิ่งนี้มีจุดประสงค์สองประการ: inline

  1. มันทำหน้าที่เป็นคำสั่งคอมไพเลอร์ที่แนะนำ (แต่ไม่จำเป็น) ว่าคอมไพเลอร์แทนที่เนื้อหาของฟังก์ชันแบบอินไลน์โดยดำเนินการขยายแบบอินไลน์กล่าวคือ โดยการแทรกโค้ดฟังก์ชันที่ที่อยู่ของการเรียกใช้ฟังก์ชันแต่ละครั้ง ซึ่งจะช่วยประหยัดค่าใช้จ่ายของฟังก์ชัน เรียก. ในส่วนนี้มีความคล้ายคลึงกับregister ตัวระบุคลาสหน่วยเก็บข้อมูลซึ่งให้คำแนะนำในการปรับให้เหมาะสมในทำนองเดียวกัน[1]
  2. วัตถุประสงค์ประการที่สองinlineคือการเปลี่ยนพฤติกรรมการเชื่อมโยง รายละเอียดเรื่องนี้ซับซ้อน นี่เป็นสิ่งจำเป็นเนื่องจากการคอมไพล์ + โมเดลการเชื่อมโยงแยกจาก C/C++ โดยเฉพาะเนื่องจากคำจำกัดความ (เนื้อความ) ของฟังก์ชันจะต้องทำซ้ำในหน่วยการแปล ทั้งหมด ที่ใช้งาน เพื่อให้สามารถอินไลน์ระหว่างการคอมไพล์ซึ่งหากฟังก์ชันมีภายนอกการเชื่อมโยงทำให้เกิดการชนกันระหว่างการเชื่อมโยง (ละเมิดเอกลักษณ์ของสัญลักษณ์ภายนอก) C และ C++ (และภาษาถิ่น เช่น GNU C และ Visual C++) แก้ไขปัญหานี้ด้วยวิธีที่แตกต่างกัน[1]

ตัวอย่าง

ฟังinlineก์ชั่นสามารถเขียนด้วยภาษา C หรือ C++ ได้ดังนี้:

การแลกเปลี่ยนโมฆะแบบอินไลน์( int * m , int * n ) { int tmp = * m ; * ม. = * ; * n = ทีเอ็มพี; -     

       
      
      

แล้วมีข้อความดังต่อไปนี้

สลับ( & x , & y ); 

อาจถูกแปลเป็น (หากคอมไพลเลอร์ตัดสินใจทำการอินไลน์ ซึ่งโดยทั่วไปจะต้องมีการเปิดใช้งานการปรับให้เหมาะสม):

inttmp = x ;x = ; y = ทีเอ็มพี;   
  
  

เมื่อใช้อัลกอริธึมการเรียงลำดับที่ทำการแลกเปลี่ยนจำนวนมาก สิ่งนี้จะช่วยเพิ่มความเร็วในการดำเนินการได้

การสนับสนุนมาตรฐาน

C++และC99แต่ไม่ใช่รุ่นก่อนK&R CและC89มีการรองรับinlineฟังก์ชันต่างๆ แม้ว่าจะมีความหมายต่างกันก็ตาม ในทั้งสองกรณีinlineจะไม่บังคับการอินไลน์ คอมไพเลอร์มีอิสระที่จะเลือกที่จะไม่อินไลน์ฟังก์ชันเลย หรือในบางกรณีเท่านั้น คอมไพเลอร์ที่แตกต่างกันจะแตกต่างกันไปตามความซับซ้อนของฟังก์ชันที่สามารถจัดการแบบอินไลน์ได้ คอมไพเลอร์ C++ หลัก เช่นMicrosoft Visual C++และGCCรองรับตัวเลือกที่ช่วยให้คอมไพเลอร์อินไลน์ฟังก์ชันที่เหมาะสมใดๆ โดยอัตโนมัติ แม้ว่าจะไม่ได้ทำเครื่องหมายว่าเป็นinlineฟังก์ชัน ก็ตาม อย่างไรก็ตาม การละเว้นinlineคีย์เวิร์ดเพื่อให้คอมไพเลอร์ทำการตัดสินใจแบบอินไลน์ทั้งหมดนั้นเป็นไปไม่ได้ เนื่องจากตัวลิงก์จะบ่นเกี่ยวกับคำจำกัดความที่ซ้ำกันในหน่วยการแปลที่แตกต่างกัน เนื่องจากinlineไม่เพียงแต่ให้คำใบ้แก่คอมไพลเลอร์ว่าฟังก์ชันควรถูกอินไลน์เท่านั้น แต่ยังมีผลกระทบต่อว่าคอมไพลเลอร์จะสร้างสำเนานอกบรรทัดของฟังก์ชันที่เรียกได้หรือไม่ (ดูคลาสหน่วยเก็บข้อมูลของฟังก์ชันอินไลน์)

ส่วนขยายที่ไม่เป็นมาตรฐาน

GNU Cซึ่งเป็นส่วนหนึ่งของภาษาถิ่น gnu89 ที่นำเสนอ ได้รับการรองรับinlineเป็นส่วนขยายของ C89 อย่างไรก็ตาม ความหมายแตกต่างจากทั้ง C++ และ C99 armcc ในโหมด C90 ยังนำเสนอinlineเป็นส่วนขยายที่ไม่ได้มาตรฐานด้วยความหมายที่แตกต่างจาก gnu89 และ C99

การใช้งานบางอย่างจัดให้มีวิธีการบังคับให้คอมไพเลอร์อินไลน์ฟังก์ชัน โดยปกติจะใช้วิธีระบุการประกาศเฉพาะการใช้งาน:

  • ไมโครซอฟต์วิชวลซี++:__forceinline
  • gcc หรือ clang: __attribute__((always_inline))หรือ__attribute__((__always_inline__))อันหลังนี้มีประโยชน์เพื่อหลีกเลี่ยงความขัดแย้งกับมาโครที่ผู้ใช้กำหนดalways_inlineชื่อ

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

การบังคับอินไลน์จะมีประโยชน์หาก:

  • inlineไม่ได้รับความเคารพจากคอมไพเลอร์ (ถูกละเว้นโดยตัววิเคราะห์ต้นทุน/ผลประโยชน์ของคอมไพเลอร์)
  • ผลลัพธ์แบบอินไลน์เป็นสิ่งจำเป็นสำหรับการเพิ่มประสิทธิภาพ

สำหรับการเคลื่อนย้ายโค้ด อาจใช้คำสั่งตัวประมวลผลล่วงหน้าต่อไปนี้:

#ifdef _MSC_VER 
#define forceinline __forceinline #elif กำหนด(__GNUC__) #define forceinline อินไลน์ __attribute__((__always_inline__)) #elif กำหนด(__CLANG__) #if __has_attribute(__always_inline__) #define forceinline อินไลน์ __attribute__((__always_inline__)) #else #define forceinline อินไลน์#endif #else #กำหนดแรงอินไลน์ อินไลน์#endif    

    

    
        
    
        
    

    

คลาสหน่วยเก็บข้อมูลของฟังก์ชันอินไลน์

static inlineมีผลเหมือนกันในภาษา C และ C ++ ทั้งหมด มันจะปล่อยฟังก์ชันที่มองเห็นได้เฉพาะเครื่อง (ไม่อยู่ในบรรทัดของ) หากจำเป็น

inlineคอมไพลเลอร์สามารถละเว้น ตัวระบุและสร้างการเรียกใช้ฟังก์ชันในภาษา C และ C++ ทั้งหมดได้ โดยไม่คำนึงถึงคลาสหน่วยเก็บข้อมูล

ผลกระทบของคลาสการจัดเก็บข้อมูลexternเมื่อนำไปใช้หรือไม่ใช้กับinlineฟังก์ชันจะแตกต่างกันระหว่างภาษา C [2]และ C++ [3]

C99

ใน C99 ฟังก์ชันที่กำหนดinlineจะไม่เกิดขึ้น และฟังก์ชันที่กำหนดextern inlineจะปล่อยฟังก์ชันที่มองเห็นได้จากภายนอกเสมอ ไม่เหมือนกับใน C++ ไม่มีทางที่จะขอให้ส่งฟังก์ชันที่มองเห็นได้จากภายนอกที่ใช้ร่วมกันระหว่างหน่วยการแปลเมื่อจำเป็นเท่านั้น

หากinlineการประกาศผสมกับextern inlineการประกาศหรือการประกาศอย่างไม่มีเงื่อนไข (เช่น โดยไม่มีinlineตัวระบุหรือคลาสการจัดเก็บข้อมูล) หน่วยการแปลจะต้องมีคำจำกัดความ (ไม่ว่าจะไม่มีเงื่อนไขinlineหรือextern inline) และฟังก์ชันที่มองเห็นได้จากภายนอกจะถูกปล่อยออกมา

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

เพื่อป้องกัน ไม่ ให้โค้ดที่ไม่สามารถเข้าถึงได้ถูกเพิ่มลงในไฟล์เรียกทำงานขั้นสุดท้ายหากการใช้งานฟังก์ชันทั้งหมดเป็นแบบอินไลน์ ขอแนะนำ[3]ให้วางไฟล์อ็อบเจ็กต์ของไฟล์ .c ดังกล่าวทั้งหมดที่มีextern inlineฟังก์ชันเดียวลงใน ไฟล์ ไลบรารีแบบสแตติกโดยทั่วไปจะมีar rcs, จากนั้นเชื่อมโยงกับไลบรารีนั้นแทนไฟล์อ็อบเจ็กต์แต่ละไฟล์ นั่นทำให้เฉพาะไฟล์อ็อบเจ็กต์เท่านั้นที่จะเชื่อมโยงที่จำเป็นจริง ๆ ตรงกันข้ามกับการเชื่อมโยงไฟล์อ็อบเจ็กต์โดยตรง ซึ่งทำให้รวมไว้ในไฟล์ปฏิบัติการเสมอ อย่างไรก็ตาม ต้องระบุไฟล์ไลบรารีหลังจากไฟล์อ็อบเจ็กต์อื่น ๆ ทั้งหมดในบรรทัดคำสั่งตัวเชื่อมโยง เนื่องจากการเรียกจากไฟล์อ็อบเจ็กต์ที่ระบุหลังไฟล์ไลบรารีไปยังฟังก์ชันจะไม่ได้รับการพิจารณาโดยตัวเชื่อมโยง การเรียกจากinlineฟังก์ชันไปยังฟังก์ชันอื่นinlineจะได้รับการแก้ไขโดยตัวเชื่อมโยงโดยอัตโนมัติ ( sตัวเลือกในar rcsการรับรองสิ่งนี้)

ทางเลือกอื่นคือการใช้การเพิ่มประสิทธิภาพเวลาลิงก์แทนไลบรารี gcc จัดเตรียมแฟล็ก-Wl,--gc-sectionsเพื่อละเว้นส่วนที่ไม่ได้ใช้ฟังก์ชันทั้งหมด นี่จะเป็นกรณีของไฟล์อ็อบเจ็กต์ที่มีโค้ดของextern inlineฟังก์ชัน เดียวที่ไม่ได้ใช้ อย่างไรก็ตาม มันยังลบส่วนที่ไม่ได้ใช้ทั้งหมดออกจากไฟล์อ็อบเจ็กต์อื่น ๆ ทั้งหมด ไม่ใช่แค่ส่วนที่เกี่ยวข้องกับextern inlineฟังก์ชัน ที่ไม่ได้ใช้ (อาจต้องการเชื่อมโยงฟังก์ชันต่างๆ เข้ากับไฟล์ปฏิบัติการที่โปรแกรมเมอร์จะเรียกใช้จากดีบักเกอร์ แทนที่จะเรียกโดยตัวโปรแกรมเอง เช่น เพื่อตรวจสอบสถานะภายในของโปรแกรม) ด้วยวิธีนี้ ก็เป็นไปได้เช่นกัน เพื่อใช้ไฟล์ .c ไฟล์เดียวที่มีextern inlineฟังก์ชันทั้งหมด แทนที่จะใช้ไฟล์ .c เพียงไฟล์เดียวต่อฟังก์ชัน จากนั้นจะต้องคอมไพล์ไฟล์ด้วย-fdata-sections -ffunction-sections. อย่างไรก็ตาม หน้าคู่มือ gcc เตือนเกี่ยวกับเรื่องนั้น โดยระบุว่า "ใช้ตัวเลือกเหล่านี้เมื่อมีประโยชน์อย่างมากจากการทำเช่นนั้นเท่านั้น"

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

gnu89

ความหมายของ gnu89 inlineและextern inlineโดยพื้นฐานแล้วตรงกันข้ามกับความหมายใน C99 เลย[4]ยกเว้นว่า gnu89 อนุญาตให้นิยามextern inlineฟังก์ชันใหม่เป็นฟังก์ชันที่ไม่มีเงื่อนไข ในขณะที่ C99 inlineไม่อนุญาต[5]ดังนั้น gnu89 extern inlineที่ไม่มีคำจำกัดความใหม่ก็เหมือนกับ C99 inlineและ gnu89 inlineก็เหมือนกับ C99 extern inline; กล่าวอีกนัยหนึ่ง ใน gnu89 ฟังก์ชันที่กำหนดinlineจะเป็นเสมอ และฟังก์ชันที่กำหนดextern inlineจะไม่ปล่อยฟังก์ชันที่มองเห็นได้จากภายนอก เหตุผลก็คือว่ามันตรงกับตัวแปร โดยที่พื้นที่เก็บข้อมูลจะไม่ถูกจองไว้หากถูกกำหนดเป็นexternและเสมอหากกำหนดโดยไม่มี ในทางตรงกันข้าม เหตุผลของ C99 ก็คือ มันจะน่าประหลาดใจถ้าการใช้inlineจะมีผลข้างเคียง นั่นคือการปล่อยฟังก์ชันเวอร์ชันที่ไม่อยู่ในบรรทัดออกมาเสมอ ซึ่งตรงกันข้ามกับที่ชื่อของมันบอกไว้

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

gcc จนถึงและรวมถึงเวอร์ชัน 4.2 ใช้inlineซีแมนทิกส์ gnu89 แม้ว่า-std=c99จะมีการระบุอย่างชัดเจน ก็ตาม [6]ด้วยเวอร์ชัน 5 [5] gcc เปลี่ยนจาก gnu89 เป็นภาษาถิ่น gnu11 ทำให้เปิดใช้งานinlineซีแมนทิกส์ C99 ได้อย่างมีประสิทธิภาพตามค่าเริ่มต้น หากต้องการใช้ซีแมนทิกส์ gnu89 แทน จะต้องเปิดใช้งานอย่างชัดเจน ไม่ว่าจะด้วย-std=gnu89หรือเพื่อให้มีผลกับอินไลน์เท่านั้น-fgnu89-inlineหรือโดยการเพิ่ม แอตทริบิวต์ลงใน การประกาศgnu_inlineทั้งหมด เพื่อ ให้inlineแน่ใจว่าซีแมนทิกส์ C99 สามารถใช้-std=c99, หรือ(ไม่มี ) ได้ [3]-std=c11-std=gnu99-std=gnu11-fgnu89-inline

ซี++

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

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

อาร์มซีซี

armcc ในโหมด C90 จัดเตรียมextern inlineและinlineความหมายที่เหมือนกับใน C ++: คำจำกัดความดังกล่าวจะปล่อยฟังก์ชันที่ใช้ร่วมกันระหว่างหน่วยการแปลหากจำเป็น ในโหมด C99 จะextern inlineส่งเสียงฟังก์ชันออกมาเสมอ แต่เช่นเดียวกับใน C++ ฟังก์ชันจะถูกแชร์ระหว่างหน่วยการแปล ดังนั้นจึงสามารถกำหนดฟังก์ชันเดียวกันextern inlineในหน่วยการแปลที่แตกต่างกันได้[7]สิ่งนี้ตรงกับพฤติกรรมดั้งเดิมของคอมไพเลอร์ Unix C [8]สำหรับexternตัวแปรโกลบอลที่ไม่ได้กำหนดนิยาม หลายตัวที่ไม่ได้กำหนดค่าเริ่มต้น

ข้อ จำกัด

การรับที่อยู่ของinlineฟังก์ชันต้องใช้โค้ดสำหรับสำเนาที่ไม่อยู่ในบรรทัดของฟังก์ชันนั้นจึงจะปล่อยออกมาไม่ว่าในกรณีใด

ใน C99 ฟังก์ชัน inlineor extern inlineจะต้องไม่เข้าถึงstaticตัวแปรส่วนกลางหรือกำหนดconst staticตัวแปรที่ไม่ใช่ภายในเครื่องconst staticตัวแปรท้องถิ่นอาจเป็นหรือไม่ใช่วัตถุที่แตกต่างกันในหน่วยการแปลที่แตกต่างกัน ขึ้นอยู่กับว่าฟังก์ชันนั้นอยู่ในบรรทัดหรือมีการโทรเกิดขึ้นหรือไม่ เฉพาะstatic inlineคำจำกัดความเท่านั้นที่สามารถอ้างอิงตัวระบุที่มีการเชื่อมโยงภายในโดยไม่มีข้อจำกัด สิ่งเหล่านั้นจะเป็นวัตถุที่แตกต่างกันในแต่ละหน่วยการแปล ในภาษา C++ อนุญาตให้ใช้ทั้ง ภาษาท้องถิ่น constและภาษาท้องถิ่นconst staticได้ และอ้างอิงถึงวัตถุเดียวกันในหน่วยการแปลทั้งหมด

gcc ไม่สามารถทำงานแบบอินไลน์ได้หาก[3]

  1. พวกมันแปรปรวน
  2. ใช้alloca
  3. ใช้คำนวณgoto
  4. ใช้ที่ไม่ใช่ของท้องถิ่นgoto
  5. ใช้ฟังก์ชันที่ซ้อนกัน
  6. ใช้setjmp
  7. ใช้__builtin_longjmp
  8. ใช้__builtin_returnหรือ
  9. ใช้__builtin_apply_args

ตามข้อกำหนดของ Microsoft ที่ MSDN นั้น MS Visual C++ ไม่สามารถอินไลน์ได้ (ไม่ใช่แม้แต่กับ__forceinline) ถ้า

  1. ฟังก์ชันหรือตัวเรียกถูกคอมไพล์ด้วย /Ob0 (ตัวเลือกเริ่มต้นสำหรับการสร้างการดีบัก)
  2. ฟังก์ชันและผู้เรียกใช้การจัดการข้อยกเว้น ประเภทต่างๆ (การจัดการข้อยกเว้น C++ ในที่หนึ่ง การจัดการข้อยกเว้นที่มีโครงสร้างในอีกที่หนึ่ง)
  3. ฟังก์ชันนี้มีรายการอาร์กิวเมนต์ที่แปรผันได้
  4. ฟังก์ชันนี้ใช้การประกอบแบบอินไลน์เว้นแต่จะคอมไพล์ด้วย /Og, /Ox, /O1 หรือ /O2
  5. ฟังก์ชันเป็นแบบเรียกซ้ำและไม่ได้มาพร้อมกับ#pragma inline_recursion(on). ด้วย Pragma ฟังก์ชันแบบเรียกซ้ำจะถูกอินไลน์ไปที่ความลึกเริ่มต้นที่ 16 การเรียก หากต้องการลดความลึกของการฝัง ให้ใช้inline_depthpragma
  6. ฟังก์ชันนี้เป็นเสมือนและถูกเรียกแบบเสมือน สามารถเรียกโดยตรงไปยังฟังก์ชันเสมือนได้ในบรรทัด
  7. โปรแกรมรับที่อยู่ของฟังก์ชันและทำการโทรผ่านตัวชี้ไปยังฟังก์ชัน การเรียกโดยตรงไปยังฟังก์ชันที่ได้รับที่อยู่ของตนสามารถอินไลน์ได้
  8. ฟังก์ชันนี้ยังถูกทำเครื่องหมายด้วย__declspecตัวแก้ไข เปล่าอีกด้วย

ปัญหา

นอกจากปัญหาเกี่ยวกับการขยายแบบอินไลน์โดยทั่วไปแล้ว (ดูการขยายแบบอินไลน์ § ผลกระทบต่อประสิทธิภาพการทำงาน ) inlineฟังก์ชั่นที่เป็นคุณลักษณะภาษาอาจไม่มีคุณค่าเท่าที่ควร ด้วยเหตุผลหลายประการ:

  • บ่อยครั้งที่คอมไพเลอร์อยู่ในตำแหน่งที่ดีกว่ามนุษย์ในการตัดสินใจว่าควรฝังฟังก์ชันใดฟังก์ชันหนึ่งไว้หรือไม่ บางครั้งคอมไพเลอร์อาจไม่สามารถอินไลน์ฟังก์ชันได้มากเท่าที่โปรแกรมเมอร์ระบุ
  • จุดสำคัญที่ควรทราบก็คือโค้ด (ของฟังก์ชันinline) จะถูกเปิดเผยต่อไคลเอนต์ (ฟังก์ชันการโทร)
  • เมื่อฟังก์ชันต่างๆ พัฒนาขึ้น ฟังก์ชันเหล่านี้อาจเหมาะสำหรับการฝังในตำแหน่งที่ไม่เคยมีมาก่อน หรือไม่เหมาะสำหรับการฝังในตำแหน่งที่เคยเป็นมาก่อนอีกต่อไป แม้ว่าฟังก์ชันแบบอินไลน์หรือยกเลิกการอินไลน์จะง่ายกว่าการแปลงเป็นและจากมาโคร แต่ก็ยังต้องมีการบำรุงรักษาเพิ่มเติม ซึ่งโดยทั่วไปแล้วจะให้ประโยชน์ค่อนข้างน้อย
  • ฟังก์ชันอินไลน์ที่ใช้ในการขยายในระบบการคอมไพล์แบบ C ดั้งเดิมสามารถเพิ่มเวลาในการคอมไพล์ได้ เนื่องจากการเป็นตัวแทนระดับกลางของเนื้อหาจะถูกคัดลอกลงในแต่ละไซต์การโทร
  • ข้อมูลจำเพาะของinlineC99 จำเป็นต้องมีคำจำกัดความภายนอกของฟังก์ชันเพียงคำเดียวเท่านั้น หากมีการใช้งานที่ไหนสักแห่ง หากโปรแกรมเมอร์ไม่ได้ให้คำจำกัดความดังกล่าว อาจนำไปสู่ข้อผิดพลาดของลิงก์เกอร์ได้ง่าย กรณีนี้อาจเกิดขึ้นได้เมื่อปิดการเพิ่มประสิทธิภาพ ซึ่งโดยทั่วไปจะป้องกันการแทรกในบรรทัด ในทางกลับกัน การเพิ่มคำจำกัดความอาจทำให้โค้ดไม่สามารถเข้าถึงได้หากโปรแกรมเมอร์ไม่หลีกเลี่ยงอย่างระมัดระวัง โดยใส่ไว้ในไลบรารีสำหรับลิงก์ ใช้การเพิ่มประสิทธิภาพเวลาลิงก์static inlineหรือ
  • ในภาษา C++ จำเป็นต้องกำหนดinlineฟังก์ชันในทุกโมดูล (หน่วยการแปล) ที่ใช้งานฟังก์ชันดังกล่าว ในขณะที่ฟังก์ชันธรรมดาจะต้องกำหนดไว้ในโมดูลเดียวเท่านั้น มิฉะนั้นจะไม่สามารถคอมไพล์โมดูลเดียวโดยแยกจากโมดูลอื่นๆ ทั้งหมดได้ สิ่งนี้อาจทำให้ไฟล์อ็อบเจ็กต์แต่ละไฟล์มีสำเนาของโค้ดของฟังก์ชัน สำหรับแต่ละโมดูลที่มีการใช้งานบางอย่างที่ไม่สามารถอินไลน์ได้ ขึ้นอยู่กับคอมไพลเลอร์
  • ในซอฟต์แวร์แบบฝังบ่อยครั้งจำเป็นต้องวางฟังก์ชันบางอย่างไว้ในส่วนของโค้ดบางส่วนโดยใช้คำสั่งคอมไพเลอร์พิเศษ เช่น คำสั่ง "pragma" บางครั้ง ฟังก์ชันในส่วนหน่วยความจำหนึ่งอาจจำเป็นต้องเรียกใช้ฟังก์ชันในส่วนหน่วยความจำอื่น และหากการอินไลน์ของฟังก์ชันที่ถูกเรียกเกิดขึ้น โค้ดของฟังก์ชันที่ถูกเรียกอาจไปจบลงในส่วนที่ไม่ควรอยู่ ตัวอย่างเช่น เซ็กเมนต์หน่วยความจำประสิทธิภาพสูงอาจถูกจำกัดอย่างมากในพื้นที่โค้ด และหากฟังก์ชันที่อยู่ในพื้นที่ดังกล่าวเรียกฟังก์ชันขนาดใหญ่อื่นที่ไม่ได้หมายถึงให้อยู่ในส่วนประสิทธิภาพสูง และฟังก์ชันที่ถูกเรียกได้รับการอินไลน์อย่างไม่เหมาะสม ดังนั้น นี่อาจทำให้เซ็กเมนต์หน่วยความจำประสิทธิภาพสูงหมดพื้นที่โค้ด ด้วยเหตุนี้ บางครั้งจึงจำเป็นต้องตรวจสอบให้แน่ใจว่าฟังก์ชันต่างๆ จะไม่อยู่ในบรรทัด

คำคม

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

—  ISO/IEC 14882:2011 มาตรฐาน C++ ปัจจุบัน หัวข้อ 7.1.2

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

...  คำจำกัดความอินไลน์ไม่ได้ให้คำจำกัดความภายนอกสำหรับฟังก์ชัน และไม่ห้ามคำจำกัดความภายนอกในหน่วยการแปลอื่น คำจำกัดความแบบอินไลน์เป็นทางเลือกให้กับคำจำกัดความภายนอก ซึ่งนักแปลอาจใช้เพื่อดำเนินการเรียกฟังก์ชันในหน่วยการแปลเดียวกัน ไม่ได้ระบุว่าการเรียกฟังก์ชันใช้คำจำกัดความแบบอินไลน์หรือคำจำกัดความภายนอก

—  ISO 9899:1999(E), มาตรฐาน C99, หัวข้อ 6.7.4

ดูสิ่งนี้ด้วย

อ้างอิง

  1. ↑ อับ เมเยอร์ส, แรนดี (1 กรกฎาคม พ.ศ. 2545) "C ใหม่: ฟังก์ชันอินไลน์" {{cite journal}}: ต้องการวารสารอ้างอิง|journal=( help )
  2. ^ ab "ฟังก์ชันอินไลน์ใน C"
  3. ↑ abcd "การใช้ GNU Compiler Collection (GCC): แบบอินไลน์"
  4. "Josef "Jeff" Sipek » GNU แบบอินไลน์กับ C99 อินไลน์"
  5. ^ ab "การย้ายไปยัง GCC 5 - โครงการ GNU"
  6. "เอียน แลนซ์ เทย์เลอร์ - ทำความสะอาดอินไลน์ภายนอก"
  7. "เอกสารประกอบ – ผู้พัฒนาอาวุธ".
  8. หน้าคู่มือ gcc, คำอธิบายของ-fno-common
  • จานา เดบาซิช (1 มกราคม 2548) C++ และกระบวนทัศน์การเขียนโปรแกรมเชิงวัตถุ PHI การเรียนรู้ Pvt. ไอเอสบีเอ็น 978-81-203-2871-6-
  • Sengupta, Probal (1 สิงหาคม 2547) การเขียนโปรแกรมเชิงวัตถุ: ความรู้พื้นฐานและการประยุกต์ PHI การเรียนรู้ Pvt. ไอเอสบีเอ็น 978-81-203-1258-6-
  • สเวนก์, โกรัน (2003) การเขียนโปรแกรมเชิงวัตถุ: การใช้ C++ สำหรับวิศวกรรมและเทคโนโลยี การเรียนรู้แบบ Cengage ไอเอสบีเอ็น 0-7668-3894-3-
  • บาลากูรูซามี (2013) การเขียนโปรแกรมเชิงวัตถุด้วย C++ การศึกษาทาทา แมคกรอว์-ฮิลล์ไอเอสบีเอ็น 978-1-259-02993-6-
  • เคียร์ช-พรินซ์, อุลลา; พรินซ์, ปีเตอร์ (2002) คู่มือการเขียนโปรแกรมด้วย C++ ฉบับสมบูรณ์ การเรียนรู้ของโจนส์และบาร์ตเลตต์ไอเอสบีเอ็น 978-0-7637-1817-6-
  • คองเกอร์, เดวิด (2549) การสร้างเกมด้วย C++: คำแนะนำทีละขั้นตอน ไรเดอร์ใหม่. ไอเอสบีเอ็น 978-0-7357-1434-2-
  • สกินเนอร์, มอนแทนา (1992) หนังสือ C++ ขั้นสูง ซิลิคอนกดไอเอสบีเอ็น 978-0-929306-10-0-
  • ความรัก (1 กันยายน 2548) การพัฒนาเคอร์เนลลินุกซ์ การศึกษาเพียร์สัน. ไอเอสบีเอ็น 978-81-7758-910-8-
  • เดฮูริ, สัจจิดานันทน์; จากาเดฟ, อล็อก คูมาร์; ราธ, อมิยา คูมาร์ (8 พฤษภาคม 2550) การเขียนโปรแกรมเชิงวัตถุโดยใช้ C++ PHI การเรียนรู้ Pvt. ไอเอสบีเอ็น 978-81-203-3085-6-

ลิงค์ภายนอก

  • ฟังก์ชันอินไลน์กับGNU Compiler Collection (GCC)
  • สรุปความหมาย "อินไลน์" ใน C และ C ++ โดยDavid Chisnall ผู้สนับสนุนLLVM
แปลจาก "https://en.wikipedia.org/w/index.php?title=Inline_function&oldid=1217592261"