เมื่อฉันพยายามสร้างรหัสนี้
inline void f() {}
int main()
{
f();
}
โดยใช้บรรทัดคำสั่ง
gcc -std=c99 -o a a.c
ฉันได้รับข้อผิดพลาดตัวเชื่อมโยง (ไม่ได้กำหนดอ้างอิงถึงf
) ข้อผิดพลาดจะหายไปหากฉันใช้static inline
หรือextern inline
แทนที่จะเป็นเพียงแค่inline
หรือถ้าฉันคอมไพล์ด้วย-O
(ดังนั้นฟังก์ชันจะถูกแทรกในบรรทัด)
พฤติกรรมนี้ดูเหมือนจะกำหนดไว้ในย่อหน้า 6.7.4 (6) ของมาตรฐาน C99:
หากการประกาศขอบเขตไฟล์ทั้งหมดสำหรับฟังก์ชันในหน่วยการแปลมีตัว
inline
ระบุฟังก์ชันที่ไม่มีextern
คำจำกัดความในหน่วยการแปลนั้นจะเป็นนิยามแบบอินไลน์ คำจำกัดความแบบอินไลน์ไม่ได้ให้คำจำกัดความภายนอกสำหรับฟังก์ชันและไม่ห้ามการกำหนดภายนอกในหน่วยการแปลอื่น นิยามแบบอินไลน์เป็นทางเลือกให้กับนิยามภายนอกซึ่งนักแปลอาจใช้เพื่อเรียกใช้ฟังก์ชันใด ๆ ในหน่วยการแปลเดียวกัน ไม่ได้ระบุว่าการเรียกใช้ฟังก์ชันใช้นิยามอินไลน์หรือนิยามภายนอก
ถ้าฉันเข้าใจทั้งหมดนี้อย่างถูกต้องหน่วยคอมไพล์ที่มีฟังก์ชันที่กำหนดไว้inline
ในตัวอย่างด้านบนจะคอมไพล์อย่างสม่ำเสมอก็ต่อเมื่อมีฟังก์ชันภายนอกที่มีชื่อเดียวกันและฉันไม่เคยรู้ว่าฟังก์ชันของตัวเองหรือฟังก์ชันภายนอกถูกเรียกใช้
พฤติกรรมนี้ไม่โง่อย่างสมบูรณ์หรือไม่? การกำหนดฟังก์ชันinline
โดยไม่มีstatic
หรือextern
ใน C99 มีประโยชน์หรือไม่? ฉันพลาดอะไรไปรึเปล่า?
สรุปคำตอบ
แน่นอนว่าฉันพลาดอะไรบางอย่างไปและพฤติกรรมก็ไม่ได้บ้าคลั่ง :)
ตามที่Nemo อธิบายแนวคิดคือการกำหนดนิยามของฟังก์ชัน
inline void f() {}
ในไฟล์ส่วนหัวและมีเพียงการประกาศเท่านั้น
extern inline void f();
ในไฟล์. c ที่เกี่ยวข้อง เฉพาะการextern
ประกาศเท่านั้นที่ทริกเกอร์การสร้างรหัสไบนารีที่มองเห็นได้ภายนอก และไม่มีการใช้งานinline
ในไฟล์. c แต่มีประโยชน์เฉพาะในส่วนหัวเท่านั้น
ในฐานะที่เป็นเหตุผลของคณะกรรมการ C99 ที่ยกมาในโจนาธานตอบ explicates, inline
เป็นข้อมูลเกี่ยวกับ optimisations คอมไพเลอร์ที่ต้องใช้ความหมายของฟังก์ชั่นที่จะสามารถมองเห็นได้ที่เว็บไซต์ของการโทร สิ่งนี้สามารถทำได้โดยการใส่คำจำกัดความไว้ในส่วนหัวเท่านั้นและแน่นอนว่าคำจำกัดความในส่วนหัวจะต้องไม่ปล่อยรหัสทุกครั้งที่คอมไพเลอร์มองเห็น แต่เนื่องจากคอมไพลเลอร์ไม่ได้ถูกบังคับให้อินไลน์ฟังก์ชันจึงต้องมีนิยามภายนอกอยู่ที่ไหนสักแห่ง