ฟังก์ชั่นการส่งคืนสตริงสไตล์ที่ดี?


11

ในโปรแกรม C ของฉันฉันมักต้องการวิธีในการสร้างการแสดงสตริงของ ADT ของฉัน แม้ว่าฉันไม่จำเป็นต้องพิมพ์สตริงไปที่หน้าจอ แต่อย่างใดมันก็เรียบร้อยที่จะมีวิธีการดังกล่าวสำหรับการดีบั๊ก ฟังก์ชันประเภทนี้มักเกิดขึ้น

char * mytype_to_string( const mytype_t *t );

ฉันรู้จริงว่าฉันมี (อย่างน้อย) สามตัวเลือกที่นี่เพื่อจัดการหน่วยความจำสำหรับสตริงที่จะกลับมา

ทางเลือก 1: การจัดเก็บสตริงส่งคืนในอาร์เรย์ char แบบคงที่ในฟังก์ชัน ฉันไม่ต้องการคิดมากนักยกเว้นว่าสตริงนั้นจะถูกเขียนทับทุกครั้งที่โทร ซึ่งอาจเป็นปัญหาในบางโอกาส

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

ทางเลือก 3: ส่งผ่านตัวชี้ไปยังบัฟเฟอร์และให้ผู้เรียกจัดสรรบัฟเฟอร์นั้น ชอบ:

char * mytype_to_string( const mytype_t *mt, char *buf, size_t buflen ); 

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

แล้วฉันควรเลือกแบบไหนดี? ทำไม? มีมาตรฐานที่ไม่เป็นลายลักษณ์อักษรในหมู่นักพัฒนา C หรือไม่


3
เพียงบันทึกเชิงสังเกตระบบปฏิบัติการส่วนใหญ่ใช้ตัวเลือก 3 - ผู้โทรจัดสรรบัฟเฟอร์ แต่อย่างใด; บอกตัวชี้บัฟเฟอร์และความจุ callee เติมบัฟเฟอร์และส่งคืนความยาวที่แท้จริงของสตริงหากบัฟเฟอร์ไม่เพียงพอ ตัวอย่าง: sysctlbynameใน OS X และ iOS
rwong

คำตอบ:


11

วิธีการที่ฉันเห็นส่วนใหญ่คือ 2 และ 3

บัฟเฟอร์ที่ผู้ใช้จัดหามานั้นค่อนข้างใช้งานง่าย:

char[128] buffer;
mytype_to_string(mt, buffer, 128);

แม้ว่าการใช้งานส่วนใหญ่จะคืนค่าจำนวนบัฟเฟอร์ที่ใช้

ตัวเลือกที่ 2 จะช้าลงและเป็นอันตรายเมื่อใช้ไลบรารีที่ลิงก์แบบไดนามิกซึ่งพวกเขาอาจใช้ runtimes ที่แตกต่างกัน (และ heaps ที่แตกต่างกัน) ดังนั้นคุณจึงไม่สามารถปลดปล่อยสิ่งที่ malloced ในห้องสมุดอื่นได้ฟรี นี่ต้องใช้free_string(char*)ฟังก์ชันเพื่อจัดการกับมัน


ขอบคุณ! ฉันคิดว่าฉันชอบ Alternative 3 ที่ดีที่สุดเช่นกัน อย่างไรก็ตามฉันต้องการที่จะสามารถทำสิ่งต่าง ๆ เช่น: printf("MyType: %s\n", mytype_to_string( mt, buf, sizeof(buf));และด้วยเหตุนี้ฉันไม่ต้องการคืนความยาวที่ใช้ แต่เป็นตัวชี้ไปยังสตริง ความคิดเห็นห้องสมุดแบบไดนามิกเป็นสิ่งสำคัญมาก
ØysteinSchønning-Johansen

สิ่งนี้ไม่ควรที่จะsizeof(buffer) - 1ตอบสนองต่อ\0ปลายทางหรือไม่
Michael-O

1
@ Michael-O ไม่มีคำที่เป็นโมฆะรวมอยู่ในขนาดบัฟเฟอร์หมายความว่าสตริงสูงสุดที่สามารถใส่ได้คือ 1 น้อยกว่าขนาดที่ส่งผ่าน นี่คือรูปแบบที่ฟังก์ชันสตริงที่ปลอดภัยในไลบรารีมาตรฐานเช่นการsnprintfใช้งาน
วงล้อประหลาด

@ ratchetfreak ขอบคุณสำหรับการชี้แจง ยินดีที่จะขยายคำตอบด้วยภูมิปัญญานั้น
Michael-O

0

แนวคิดการออกแบบเพิ่มเติมสำหรับ # 3

เมื่อเป็นไปได้ยังมีขนาดสูงสุดที่จำเป็นสำหรับmytypeในแฟ้ม .h mytype_to_string()เดียวกับ

#define MYTYPE_TO_STRING_SIZE 256

ตอนนี้ผู้ใช้สามารถรหัสตาม

char buf[MYTYPE_TO_STRING_SIZE];
puts(mytype_to_string(mt, buf, sizeof buf));

ใบสั่ง

ขนาดของอาเรย์เมื่อแรกให้สำหรับประเภท VLA

char * mytype_to_string( const mytype_t *mt, size_t bufsize, char *buf[bufsize]); 

ไม่สำคัญกับมิติเดียว แต่มีประโยชน์กับ 2 หรือมากกว่า

void matrix(size_t row, size_t col, double matrix[row][col]);

ฉันจำได้ว่าการอ่านหนังสือที่มีขนาดก่อนเป็นสำนวนที่ต้องการในซีต่อไปต้องการค้นหาอ้างอิงนั้น ....


0

นอกเหนือจากคำตอบที่ยอดเยี่ยมของ @ ratchetfreak ฉันจะชี้ให้เห็นว่าทางเลือก # 3 เป็นไปตามกระบวนทัศน์ / รูปแบบที่คล้ายกันเป็นฟังก์ชันไลบรารีมาตรฐาน C

ตัวอย่างเช่นstrncpy.

char * strncpy ( char * destination, const char * source, size_t num );

การทำตามกระบวนทัศน์เดียวกันนี้จะช่วยลดภาระการรับรู้สำหรับนักพัฒนาใหม่ (หรือแม้แต่ตัวคุณในอนาคต) เมื่อพวกเขาต้องการใช้ฟังก์ชันของคุณ

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

char * mytype_to_string( char *buf, const mytype_t *mt, size_t buflen ); 

-2

นอกจากความจริงที่ว่าสิ่งที่คุณกำลังเสนอให้ทำคือมีกลิ่นรหัสที่ไม่ดีตัวเลือก 3 ที่ดีที่สุดสำหรับฉัน ฉันคิดเช่น @ gnasher729 ว่าคุณใช้ภาษาผิด


คุณคิดว่าอะไรคือกลิ่นของรหัส? กรุณาอธิบายอย่างละเอียด
Hulk

-3

หากต้องการพูดตามจริงคุณอาจต้องการเปลี่ยนไปใช้ภาษาอื่นซึ่งการส่งคืนสตริงไม่ใช่การดำเนินการที่ซับซ้อนซับซ้อนใช้งานได้และข้อผิดพลาดได้ง่าย

คุณสามารถพิจารณา C ++ หรือ Objective-C ซึ่งคุณสามารถปล่อยโค้ดไว้ 99% ไม่เปลี่ยนแปลง

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