อะไรคือความแตกต่างระหว่างฟังก์ชัน“ คงที่” และ“ อินไลน์แบบคงที่”


123

IMO ทำให้ฟังก์ชันมีขอบเขตของหน่วยการแปลเท่านั้น

อะไรคือความแตกต่างระหว่างฟังก์ชัน "static" และ "static inline"

ทำไมinlineต้องใส่ไว้ในไฟล์ส่วนหัวไม่ใช่ใน.cไฟล์?

คำตอบ:


108

inlineสั่งให้คอมไพลเลอร์พยายามฝังเนื้อหาฟังก์ชันลงในโค้ดการเรียกแทนที่จะเรียกใช้งานจริง

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

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

ตัวอย่างเช่น:

static int Inc(int i) {return i+1};
.... // some code
int i;
.... // some more code
for (i=0; i<999999; i = Inc(i)) {/*do something here*/};

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

 int i;
 ....
 for (i=0; i<999999; i = i+1) { /* do something here */};

ข้ามการเรียกใช้ฟังก์ชันจริงและย้อนกลับ

เห็นได้ชัดว่านี่เป็นตัวอย่างเพื่อแสดงประเด็นไม่ใช่โค้ดจริง

staticหมายถึงขอบเขต ในภาษา C หมายความว่าฟังก์ชัน / ตัวแปรสามารถใช้ได้ภายในหน่วยการแปลเดียวกันเท่านั้น


4
ไม่staticหมายถึงขอบเขต ในภาษา C หมายความว่าฟังก์ชัน / ตัวแปรสามารถใช้ได้ภายในหน่วยการแปลเดียวกันเท่านั้น
littleadv

8
สิ่งสำคัญที่ควรทราบคือรหัสที่ประกาศเป็นแบบอินไลน์อยู่ในส่วนหัวโดยที่ซอร์สโค้ดปกติ (ไม่ใช่เทมเพลต) ไม่สามารถอยู่ในส่วนหัวได้โดยไม่ก่อให้เกิดข้อผิดพลาดในการกำหนดนิยามใหม่หลายรายการ ดังนั้นแม้ว่าจะประกาศบางอย่างแบบอินไลน์แม้ว่าคอมไพลเลอร์จะเลือกที่จะไม่อินไลน์ แต่ก็ยังมีการกำหนดนิยามใหม่หลายคำสั่งมาตรฐานเพื่อหลีกเลี่ยงพฤติกรรมที่เข้ามา
VoidStar

13
@VoidStar จริงๆแล้วstatic(มีหรือไม่มีinline) สามารถอยู่ในส่วนหัวได้อย่างสมบูรณ์แบบดูเหตุผลว่าทำไมไม่ เทมเพลตสำหรับ C ++ คำถามนี้เกี่ยวกับ C.
littleadv

2
@littleadv: เหตุผลหลักในการใส่คำจำกัดความของฟังก์ชันในไฟล์ส่วนหัวคือการทำให้ไม่สามารถเลือกได้ดังนั้นการทำเครื่องหมายให้ชัดเจนinlineจึงเป็นรูปแบบที่ดี imo
Christoph

10
ที่จริงแล้วinlineไม่ได้สั่งให้คอมไพเลอร์พยายามใด ๆ ในการซับใน เป็นเพียงการอนุญาตให้โปรแกรมเมอร์รวมเนื้อความฟังก์ชันไว้ในหน่วยการแปลหลายหน่วยโดยไม่ละเมิด ODR ผลข้างเคียงของสิ่งนี้คือทำให้คอมไพเลอร์เป็นไปได้เมื่อมันจะอินไลน์ฟังก์ชันจะทำสิ่งนี้ได้
Ruslan

96

ตามค่าเริ่มต้นคำจำกัดความแบบอินไลน์ใช้ได้เฉพาะในหน่วยการแปลปัจจุบัน

ถ้าคลาสหน่วยเก็บคือexternตัวระบุจะมีการเชื่อมโยงภายนอกและนิยามอินไลน์ยังให้นิยามภายนอกด้วย

ถ้าคลาสหน่วยเก็บคือstaticตัวระบุจะมีการเชื่อมโยงภายในและนิยามอินไลน์จะมองไม่เห็นในหน่วยการแปลอื่น

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

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

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

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

โดยส่วนตัวแล้วฉันใช้หลักการนี้เพื่อทำเครื่องหมายstaticคำจำกัดความของฟังก์ชันภายในส่วนหัวด้วยinlineเนื่องจากเหตุผลหลักในการใส่คำจำกัดความของฟังก์ชันในไฟล์ส่วนหัวคือการทำให้ไม่สามารถใช้งานได้

โดยทั่วไปฉันใช้คำจำกัดความของstatic inlineฟังก์ชันและstatic constอ็อบเจ็กต์นอกเหนือจากการexternประกาศภายในส่วนหัวเท่านั้น

ฉันไม่เคยเขียนinlineฟังก์ชันที่มีคลาสพื้นที่เก็บข้อมูลที่แตกต่างจากstatic.


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

1
ได้รับการโหวตให้ "use the convention to mark static function definitions in headers inline"
John Z. Li

ผมอ่านคำตอบทั้งหมดของคุณและผมก็ยังไม่ได้รับความแตกต่างระหว่างความหมายและstatic static inlineทั้งสองทำให้ความหมายมองไม่เห็นในหน่วยการแปลอื่น ๆ อะไรคือเหตุผลที่สมเหตุสมผลที่จะเขียนstatic inlineแทนstatic?
user541686

21

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

ดังนั้นฉันมักคิดว่าstaticควรใช้ในหน่วยการแปลและได้รับประโยชน์จากคอมไพเลอร์ตรวจสอบพิเศษเพื่อค้นหาฟังก์ชันที่ไม่ได้ใช้ และstatic inlineควรใช้ในไฟล์ส่วนหัวเพื่อจัดเตรียมฟังก์ชันที่สามารถเรียงกันได้ (เนื่องจากไม่มีการเชื่อมโยงภายนอก) โดยไม่ต้องออกคำเตือน

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


1
อืมยังคงมีwarning: unused function 'function' [clang-diagnostic-unused-function]สำหรับstatic inlineฟังก์ชันเมื่อสร้างด้วยclang-tidy(v8.0.1) ซึ่งใช้ในหน่วยการแปลอื่น แต่แน่นอนว่านี่เป็นหนึ่งในคำอธิบายและเหตุผลที่ดีที่สุดในการรวมstatic& inline!
DrumM

6

ใน C staticหมายถึงฟังก์ชันหรือตัวแปรที่คุณกำหนดสามารถใช้ได้เฉพาะในไฟล์นี้ (เช่นหน่วยคอมไพล์)

ดังนั้นstatic inlineหมายถึงฟังก์ชันอินไลน์ที่สามารถใช้ได้ในไฟล์นี้เท่านั้น

แก้ไข:

หน่วยคอมไพล์ควรเป็นหน่วยการแปล


2
หรือในคำแฟนซี: มีการเชื่อมโยงภายใน
K-ballo

@AlokSave: มีความแตกต่างระหว่างหน่วยการรวบรวมและหน่วยการแปลหรือไม่? ถ้าเป็นเช่นนั้นข้อใดเหมาะสมกว่าในบริบทของภาษา C ++
legends2k

ฉันเชื่อว่าthe compile unitเป็นสิ่งที่ฉันเขียนด้วยความผิดพลาดไม่มีสิ่งนั้นคำศัพท์ที่แท้จริงคือtranslation unit
shengy

คำตอบของคุณยังไม่สมบูรณ์เนื่องจากส่วนใหญ่จะใช้ในไฟล์ส่วนหัวรวมกับหน่วยการแปล
DrumM

5

ความแตกต่างอย่างหนึ่งที่ไม่ได้อยู่ที่ระดับภาษา แต่เป็นระดับการนำไปใช้งานที่ได้รับความนิยม: gcc บางเวอร์ชันจะลบstatic inlineฟังก์ชันที่ไม่ได้อ้างอิงออกจากเอาต์พุตตามค่าเริ่มต้น แต่จะยังคงใช้staticฟังก์ชันธรรมดาแม้ว่าจะไม่ได้อ้างอิงก็ตาม ฉันไม่แน่ใจว่ารุ่นนี้ แต่จากมุมมองในทางปฏิบัติมันหมายความว่ามันอาจจะเป็นความคิดที่ดีที่จะมักจะใช้inlineสำหรับstaticฟังก์ชั่นในส่วนหัว


แล้วการใช้inlineคำจำกัดความล่ะ? คุณไม่ได้ใช้มันเพื่อexternฟังก์ชั่นหรือไม่?
new_perl

สิ่งนี้ยังคงเป็นจริงกับ GCC เวอร์ชันล่าสุดหรือไม่ คำตอบของคุณจะน่าสนใจกว่านี้มากหากคุณเป็นตัวอย่างและระบุว่า GCC เวอร์ชันใดทำ
Z boson

@Zboson: ฉันไม่มีข้อมูลนั้นพร้อมใช้งานและไม่มีเวลาตั้งค่าและทดสอบเวอร์ชัน gcc จำนวนมากในขณะนี้ แต่ฉันยอมรับว่ามันจะเป็นข้อมูลที่มีประโยชน์ คุณอาจพบว่าเมื่อ gcc เริ่มปรับแต่งฟังก์ชัน / วัตถุคงที่ที่ไม่ได้ใช้เป็นครั้งแรกโดยดูที่ประวัติattribute((used))และการใช้งานเพื่ออนุญาตให้ asm อ้างอิงstaticฟังก์ชันและข้อมูลที่ไม่ได้อ้างอิงเป็นอย่างอื่น
R .. GitHub STOP HELPING ICE
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.