Fungsi mengembalikan string, gaya yang bagus?


11

Dalam program C saya, saya sering membutuhkan cara untuk membuat representasi string dari ADT saya. Bahkan jika saya tidak perlu mencetak string ke layar dengan cara apa pun, rapi untuk memiliki metode debugging seperti itu. Jadi fungsi semacam ini sering muncul.

char * mytype_to_string( const mytype_t *t );

Saya benar-benar menyadari bahwa saya memiliki (setidaknya) tiga opsi di sini untuk menangani memori agar string dapat kembali.

Alternatif 1: Menyimpan string kembali dalam array char statis dalam fungsi. Saya tidak perlu banyak berpikir, kecuali bahwa string ditimpa pada setiap panggilan. Yang mungkin menjadi masalah dalam beberapa kesempatan.

Alternatif 2: Alokasikan string pada heap dengan malloc di dalam fungsi. Benar-benar rapi karena saya tidak perlu memikirkan ukuran buffer atau penulisan ulang. Namun, saya harus ingat untuk membebaskan () string ketika selesai, dan kemudian saya juga perlu menetapkan variabel sementara sehingga saya bisa membebaskan. dan kemudian alokasi heap benar-benar jauh lebih lambat daripada alokasi stack, oleh karena itu menjadi hambatan jika ini diulang dalam satu lingkaran.

Alternatif 3: Masukkan pointer ke buffer, dan biarkan pemanggil mengalokasikan buffer itu. Suka:

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

Ini membawa lebih banyak upaya bagi penelepon. Saya juga memperhatikan bahwa alternatif ini memberi saya pilihan lain pada urutan argumen. Argumen mana yang harus saya miliki pertama dan terakhir? (sebenarnya enam kemungkinan)

Jadi, mana yang harus saya pilih? Adakah alasannya? Apakah ada semacam standar tidak tertulis di antara pengembang C?


3
Hanya catatan pengamatan, sebagian besar sistem operasi menggunakan opsi 3 - pemanggil mengalokasikan buffer bagaimanapun; memberi tahu buffer pointer dan kapasitas; callee mengisi buffer dan juga mengembalikan panjang string yang sebenarnya jika buffer tidak mencukupi. Contoh: sysctlbynamedi OS X dan iOS
rwong

Jawaban:


11

Metode yang paling banyak saya lihat adalah 2 dan 3.

Buffer yang disediakan pengguna sebenarnya cukup mudah digunakan:

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

Padahal sebagian besar implementasi akan mengembalikan jumlah buffer yang digunakan.

Opsi 2 akan lebih lambat dan berbahaya saat menggunakan pustaka yang terhubung secara dinamis di mana mereka dapat menggunakan runtime yang berbeda (dan tumpukan yang berbeda). Jadi, Anda tidak bisa membebaskan apa yang telah malloced di perpustakaan lain. Ini kemudian membutuhkan free_string(char*)fungsi untuk menghadapinya.


Terima kasih! Saya rasa saya juga suka Alternatif 3. Namun saya ingin dapat melakukan hal-hal seperti: printf("MyType: %s\n", mytype_to_string( mt, buf, sizeof(buf));dan karenanya saya tidak akan suka mengembalikan panjang yang digunakan melainkan pointer ke string. Komentar perpustakaan dinamis sangat penting.
Øystein Schønning-Johansen

Bukankah ini sizeof(buffer) - 1untuk memuaskan \0terminator?
Michael-O

1
@ Michael-O tidak ada istilah nol yang termasuk dalam ukuran buffer yang berarti bahwa string maks yang dapat dimasukkan adalah 1 kurang dari ukuran yang diteruskan. Ini adalah pola yang digunakan fungsi string aman di perpustakaan standar snprintf.
ratchet freak

@ scratchetfreak Terima kasih atas klarifikasi. Akan menyenangkan untuk memperluas jawaban dengan kebijaksanaan itu.
Michael-O

0

Ide desain tambahan untuk # 3

Bila memungkinkan, berikan juga ukuran maksimum yang diperlukan untuk mytypefile .h yang sama dengan mytype_to_string().

#define MYTYPE_TO_STRING_SIZE 256

Sekarang pengguna dapat membuat kode yang sesuai.

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

Memesan

Ukuran array, saat pertama, memungkinkan untuk tipe VLA.

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

Tidak begitu penting dengan dimensi tunggal, namun bermanfaat dengan 2 atau lebih.

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

Saya ingat pernah membaca memiliki ukuran pertama adalah idiom yang disukai dalam C. berikutnya. Perlu menemukan referensi itu ....


0

Sebagai tambahan untuk jawaban yang sangat bagus dari @ ratchetfreak, saya akan menunjukkan bahwa alternatif # 3 mengikuti paradigma / pola yang sama seperti fungsi pustaka C standar.

Sebagai contoh strncpy,.

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

Mengikuti paradigma yang sama akan membantu mengurangi beban kognitif untuk pengembang baru (atau bahkan diri Anda di masa depan) ketika mereka perlu menggunakan fungsi Anda.

Satu-satunya perbedaan dengan apa yang Anda miliki dalam posting Anda adalah bahwa destinationargumen di pustaka C cenderung didaftar pertama dalam daftar argumen. Begitu:

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

-2

Selain fakta bahwa apa yang Anda usulkan adalah bau kode yang buruk, alternatif 3 kedengarannya terbaik bagi saya. Saya juga berpikir seperti @ gnasher729 bahwa Anda menggunakan bahasa yang salah.


Apa sebenarnya yang Anda anggap sebagai bau kode? Tolong jelaskan.
Hulk

-3

Sejujurnya, Anda mungkin ingin beralih ke bahasa lain di mana mengembalikan string bukanlah operasi yang kompleks, padat karya, dan rawan kesalahan.

Anda dapat mempertimbangkan C ++ atau Objective-C di mana Anda dapat membiarkan 99% kode Anda tidak berubah.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.