การซ่อนข้อมูล
ข้อดีของการส่งกลับตัวชี้ไปยังโครงสร้างต่างจากการส่งคืนโครงสร้างทั้งหมดในคำสั่ง return ของฟังก์ชันคืออะไร
หนึ่งที่พบมากที่สุดคือที่หลบซ่อนข้อมูล C ไม่ได้พูดความสามารถในการสร้างเขตข้อมูลของstruct
ส่วนตัวให้คนเดียวให้วิธีการในการเข้าถึงพวกเขา
ดังนั้นหากคุณต้องการป้องกันไม่ให้นักพัฒนาสามารถดูและแก้ไขเนื้อหาของ Pointee ได้เช่นเดียวFILE
แล้ววิธีเดียวคือป้องกันพวกเขาจากการสัมผัสกับคำจำกัดความโดยการใช้ตัวชี้เป็นทึบแสงซึ่งมีขนาดของ Pointee และ คำนิยามไม่เป็นที่รู้จักของโลกภายนอก คำจำกัดความของFILE
จะปรากฏให้เห็นเฉพาะผู้ที่ใช้งานการดำเนินการที่ต้องการคำนิยามเช่นfopen
ในขณะที่การประกาศโครงสร้างจะปรากฏเฉพาะส่วนหัวสาธารณะ
ความเข้ากันได้ไบนารี
การซ่อนคำจำกัดความของโครงสร้างสามารถช่วยให้ห้องหายใจสามารถรักษาความเข้ากันได้ของไบนารีใน dylib API อนุญาตให้ผู้ใช้ไลบรารีสามารถเปลี่ยนฟิลด์ในโครงสร้างทึบโดยไม่ทำลายความเข้ากันได้ของไบนารีกับผู้ที่ใช้ไลบรารีเนื่องจากธรรมชาติของรหัสของพวกเขาต้องการเพียงแค่รู้ว่าพวกเขาสามารถทำอะไรกับโครงสร้างได้ไม่ว่ามันจะใหญ่แค่ไหน มันมี.
ตัวอย่างเช่นฉันสามารถใช้งานโปรแกรมโบราณบางอย่างที่สร้างขึ้นในยุค Windows 95 ในปัจจุบัน (ไม่สมบูรณ์แบบเสมอไป แต่ยังคงทำงานได้อย่างน่าประหลาดใจ) โอกาสที่รหัสบางส่วนสำหรับไบนารีโบราณเหล่านั้นใช้ตัวชี้ทึบแสงเป็นโครงสร้างที่มีขนาดและเนื้อหาเปลี่ยนแปลงไปจากยุค Windows 95 แต่โปรแกรมเหล่านี้ยังคงทำงานต่อไปใน windows รุ่นใหม่เนื่องจากพวกเขาไม่ได้สัมผัสกับเนื้อหาของโครงสร้างเหล่านั้น เมื่อทำงานในไลบรารีที่ความเข้ากันได้ของไบนารีเป็นสิ่งสำคัญโดยทั่วไปสิ่งที่ไคลเอ็นต์ไม่ได้รับอนุญาตให้เปลี่ยนแปลงโดยไม่ทำให้ความเข้ากันได้ย้อนหลัง
อย่างมีประสิทธิภาพ
การคืนโครงสร้างที่เป็น NULL นั้นยากขึ้นฉันคิดว่าหรือมีประสิทธิภาพน้อยกว่า นี่เป็นเหตุผลที่ถูกต้องหรือไม่
โดยทั่วไปแล้วจะมีประสิทธิภาพน้อยกว่าโดยสมมติว่าประเภทสามารถพอดีและจัดสรรบนสแต็กได้เว้นแต่ว่าโดยทั่วไปจะมีตัวจัดสรรหน่วยความจำแบบทั่วไปที่ใช้อยู่ด้านหลังน้อยกว่าmalloc
เช่นขนาดคงที่แทนที่จะจัดสรรหน่วยความจำขนาดรวมกัน มันเป็นความปลอดภัยของการปิดในกรณีนี้ส่วนใหญ่มีแนวโน้มที่จะช่วยให้นักพัฒนาห้องสมุดเพื่อรักษาค่าคงที่ (การค้ำประกันความคิด) FILE
ที่เกี่ยวข้องกับ
ไม่ใช่เหตุผลที่ถูกต้องอย่างน้อยที่สุดจากจุดยืนด้านประสิทธิภาพในการfopen
ส่งคืนตัวชี้เนื่องจากเหตุผลเดียวที่ส่งคืนNULL
คือเมื่อไม่สามารถเปิดไฟล์ได้ นั่นจะเป็นการเพิ่มประสิทธิภาพของสถานการณ์พิเศษเพื่อแลกกับการลดเส้นทางการดำเนินการกรณีทั่วไปทั้งหมด อาจมีเหตุผลในการเพิ่มประสิทธิภาพที่ถูกต้องในบางกรณีเพื่อทำให้การออกแบบตรงไปตรงมามากขึ้นเพื่อให้พวกเขาส่งคืนพอยน์เตอร์เพื่ออนุญาตให้NULL
ส่งคืนในบางโพสต์เงื่อนไข
สำหรับการดำเนินงานไฟล์, ค่าใช้จ่ายเป็นที่ค่อนข้างน่ารำคาญมากทีเดียวเมื่อเทียบกับการดำเนินงานไฟล์ตัวเองและคู่มือการใช้งานต้องfclose
ไม่สามารถหลีกเลี่ยงได้อยู่แล้ว ดังนั้นจึงไม่เหมือนกับที่เราสามารถช่วยลูกค้าลดความยุ่งยากในการปล่อย (ปิด) ทรัพยากรโดยการให้คำจำกัดความFILE
และคืนค่าตามจำนวนfopen
หรือคาดหวังว่าจะมีการเพิ่มประสิทธิภาพมากขึ้นเนื่องจากค่าใช้จ่ายสัมพัทธ์ของการดำเนินการไฟล์เอง .
ฮอตสปอตและการแก้ไข
สำหรับกรณีอื่น ๆ ฉันได้รวบรวมรหัส C ที่สิ้นเปลืองจำนวนมากในฐานรหัสเดิมที่มีฮอตสปอตmalloc
และแคชบังคับที่ไม่จำเป็นเนื่องจากการใช้วิธีนี้บ่อยเกินไปกับตัวชี้ทึบและจัดสรรสิ่งต่าง ๆ มากมายโดยไม่จำเป็นบนฮีป ลูปขนาดใหญ่
แนวทางปฏิบัติทางเลือกที่ฉันใช้แทนคือการเปิดเผยคำจำกัดความของโครงสร้างแม้ว่าลูกค้าไม่ได้ตั้งใจจะดัดแปลงพวกเขาโดยใช้มาตรฐานการประชุมการตั้งชื่อเพื่อสื่อสารว่าไม่มีใครควรสัมผัสฟิลด์:
struct Foo
{
/* priv_* indicates that you shouldn't tamper with these fields! */
int priv_internal_field;
int priv_other_one;
};
struct Foo foo_create(void);
void foo_destroy(struct Foo* foo);
void foo_something(struct Foo* foo);
หากมีข้อสงสัยเกี่ยวกับความเข้ากันได้ของไบนารีในอนาคตฉันก็พบว่ามันดีพอที่จะจองพื้นที่พิเศษเพิ่มเติมเพื่อวัตถุประสงค์ในอนาคตได้เช่น:
struct Foo
{
/* priv_* indicates that you shouldn't tamper with these fields! */
int priv_internal_field;
int priv_other_one;
/* reserved for possible future uses (emergency backup plan).
currently just set to null. */
void* priv_reserved;
};
พื้นที่สงวนนั้นค่อนข้างสิ้นเปลือง แต่สามารถช่วยชีวิตหากเราพบในอนาคตที่เราต้องการเพิ่มข้อมูลเพิ่มเติมFoo
โดยไม่ทำลายไบนารีที่ใช้ห้องสมุดของเรา
ในความเห็นของฉันการซ่อนข้อมูลและความเข้ากันได้ของไบนารีโดยทั่วไปแล้วเป็นเพียงเหตุผลที่ดีที่อนุญาตให้จัดสรรฮีปของโครงสร้างนอกเหนือจากโครงสร้างที่มีความยาวผันแปรได้ (ซึ่งจะต้องใช้เสมอหรืออย่างน้อยต้องใช้ หน่วยความจำบนสแต็คในรูปแบบ VLA เพื่อจัดสรร VLS) แม้แต่โครงสร้างที่มีขนาดใหญ่มักจะถูกกว่าเพื่อส่งคืนตามมูลค่าหากนั่นหมายความว่าซอฟต์แวร์ทำงานได้มากขึ้นกับหน่วยความจำร้อนบนสแต็ก และแม้ว่าพวกเขาจะไม่ถูกกว่าที่จะได้รับผลตอบแทนจากการสร้าง แต่ก็สามารถทำได้:
int foo_create(struct Foo* foo);
...
/* In the client code: */
struct Foo foo;
if (foo_create(&foo))
{
foo_something(&foo);
foo_destroy(&foo);
}
... เพื่อเริ่มต้นFoo
จากสแต็กโดยไม่มีความเป็นไปได้ของสำเนาฟุ่มเฟือย หรือลูกค้ายังมีอิสระที่จะจัดสรรFoo
บนกองหากพวกเขาต้องการด้วยเหตุผลบางอย่าง