Mengapa mengembalikan nilai pengembalian gratis?

82

Saya membaca buku ( Pemrograman dengan POSIX Threads oleh Butenhof, 1997) yang menggunakan C, dan saya menemukan baris berikut:

(void)free(data);

Di sini, datahanya sebuah pointer ke struct yang dialokasikan,

data = malloc(sizeof(my_struct_t));

Mengapa akibat freedilemparkan void?

Dari pemahaman saya tentang C, ini sepertinya tidak masuk akal karena dua alasan:

  • Fungsi gratis sudah kembali void
  • Kode tidak menggunakan nilai kembali (bahkan tidak ditugaskan ke variabel)

Buku itu ditulis pada tahun 1997. Apakah ini semacam warisan?

Penulis menyebutkan bahwa contoh dijalankan di Digital Unix 4.0d, tapi saya masih tidak bisa membayangkan alasan untuk pernah melemparkan hasil fungsi jika Anda tidak akan menggunakan hasil itu.

Adam Johnston
sumber
Beberapa penjelasan yang mungkin dapat ditemukan di sini: stackoverflow.com/questions/689677/…
Timbo
3
Karena penasaran, apa tanggal penerbitan buku C Anda? (Buku apa itu?) Jika sebelum tahun 1995, mungkin ada beberapa pembenaran untuk itu - penyusun standar C tidak ada di mana-mana sebelumnya. Jika diterbitkan setelah itu dan masih berisi pemeran (dan tidak ada penjelasan mengapa), khawatir tentang kebiasaan buruk apa lagi yang diajarkannya kepada Anda. Dapatkan buku yang lebih baru!
Jonathan Leffler
10
Sepertinya Memprogram dengan Utas POSIX
Eugene Sh.
3
@JonathanLeffler seperti yang disebutkan dalam posting asli saya, buku itu diterbitkan pada tahun 1997 dan menggunakan UNIX 4.0d. Buku ini "Programming with POSIX Threads" oleh David R. Butenhof. Sejauh ini sangat informatif dan ditulis oleh salah satu kontributor asli untuk standar thread POSIX.
Adam Johnston
6
Saya telah menggunakan salinan itu minggu lalu - ya, ini masih berguna. Itu ditulis pada puncak 'di mana-mana standar C' (saya katakan 'sekitar 1995'). 'UNIX 4.0d' terdengar seperti Digital UNIX - di situlah Butenhof bekerja, dan kata pengantar menyebutkannya. Perlakukan para pemain free()sebagai keanehan dalam buku yang tidak perlu Anda tiru. Itu semi-relevan dulu sekali, tapi itu tidak relevan lagi.
Jonathan Leffler

Jawaban:

100

Jika kita berbicara tentang freefungsi standar maka prototipenya adalah

void free(void *ptr);

Karena itu para pemain sama sekali tidak berguna.
Sekarang beberapa spekulasi.

Penulis mungkin lupa menyertakan stdlib.hheader yang menyatakan prototipe ini, sehingga kompiler menganggap tipe kembalinya sebagai int. Sekarang selama analisis statis kode ini kompiler memperingatkan tentang nilai balik yang tidak terpakai dari apa yang dianggapnya sebagai tidak voidberfungsi. Peringatan seperti itu biasanya dibungkam dengan menambahkan pemeran void.

Eugene Sh.
sumber
50
Tetapi perhatikan bahwa jika para pemain diperkenalkan karena alasan berspekulasi, maka menggunakannya untuk membungkam peringatan itu tidak benar . Compiler dalam hal ini akan menghubungkan tipe yang berbeda freedari yang sebenarnya, dengan hasil bahwa panggilan memiliki perilaku yang tidak terdefinisi (seandainya C90 semantik, di mana memanggil fungsi yang tidak dideklarasikan secara inheren tidak menunjukkan UB dalam semua kasus). Dalam prakteknya, adalah masuk akal bahwa yang akan mengakibatkan bona fide perilaku pada beberapa sistem. Solusi yang benar adalah dengan memberikan deklarasi yang benar untuk fungsi tersebut.
John Bollinger
11
Khususnya, contoh dalam "Pemrograman dengan POSIX Threads" berulang kali gagal menyertakan header standar yang relevan. Mungkin ini adalah praktik buruk oleh penulis, mereka bisa saja menggunakan pengaturan kompiler non-standar yang menyertakan semua lib standar secara default.
Lundin
74

Itu akan menjadi warisan!

Sebelum ada standar C, free()fungsinya adalah tipe (secara implisit) int- karena belum ada tipe yang dapat diandalkan voiduntuk mengembalikannya. Tidak ada nilai yang dikembalikan.

Ketika kode pertama kali dimodifikasi untuk bekerja dengan kompiler C standar, mungkin tidak termasuk <stdlib.h>(karena tidak ada sebelum standar). Kode lama akan menulis extern char *malloc();(mungkin tanpa extern) untuk fungsi alokasi (sama untuk calloc()dan realloc()), dan tidak perlu mendeklarasikan free(). Dan kode kemudian akan melemparkan nilai kembali ke jenis yang benar - karena itu diperlukan pada setidaknya beberapa sistem (termasuk yang saya pelajari C on).

Beberapa waktu kemudian, para (void)pemain ditambahkan untuk memberi tahu kompiler (atau, lebih mungkin, lint) bahwa "nilai pengembalian dari free()sengaja diabaikan" untuk menghindari keluhan. Tetapi akan lebih baik untuk menambahkan <stdlib.h>dan membiarkan deklarasi extern void free(void *vp);memberitahu lintatau kompiler bahwa tidak ada nilai untuk diabaikan.

JFTR: Kembali pada pertengahan '80 -an, ICL Perq awalnya pada arsitektur berorientasi kata dan char *alamat untuk lokasi memori adalah nomor yang sangat berbeda dari 'penunjuk apa saja' ke lokasi yang sama. Sangat penting untuk mendeklarasikan char *malloc()entah bagaimana; itu penting untuk melemparkan hasilnya dari itu ke jenis pointer lainnya. Para pemain sebenarnya mengubah angka yang digunakan oleh CPU. (Ada juga banyak kegembiraan ketika memori utama pada sistem kami ditingkatkan dari 1 MiB menjadi 2 MiB - karena kernel menggunakan sekitar 3/4 MiB, itu berarti bahwa program pengguna dapat menggunakan 1 1/4 MiB sebelum paging dll.)

Jonathan Leffler
sumber
9
Saya baru saja membuka salinan K&R, edisi 1, yang berisi implementasi free()pada hal. 177 yang secara implisit kembali int.
ex nihilo
9
Tentu saja - voidditambahkan ke beberapa sistem (Unix System III, mungkin) sebelum standar dirilis, tetapi itu bukan bagian dari C ketika K&R 1st Edn ditulis (1978). Fungsi yang tidak mengembalikan nilai dinyatakan tanpa tipe pengembalian (yang artinya dikembalikan int), dan selama Anda tidak menggunakan nilai yang tidak dikembalikan, tidak ada masalah. Standar C90 harus memperlakukan kode semacam itu sebagai valid - standar itu akan gagal jika standar tidak gagal. Tapi C99 menghapus aturan 'implisit int' dan 'deklarasi fungsi implisit'. Tidak semua kode di dunia berhasil menyusul.
Jonathan Leffler
5
Op mengklaim buku itu ditulis pada tahun 1997. Apa yang Anda bicarakan di sini adalah pra-standar awal "K&R C" dan sepertinya tidak mungkin ada orang yang akan menulis buku tentang itu sama sekali. Satu-satunya buku yang ada sejauh pengetahuan saya adalah K&R edisi pertama.
Lundin
Itu adalah praktik yang sering (jika quixotic) untuk tidak menyertakan header jika Anda pikir Anda bisa lolos dengan deklarasi implisit, karena orang berpikir itu akan mengurangi waktu pembuatan.
Spencer
Adakah yang menggunakan (void)gips untuk printf()??
Luis Colorado
11

Pemain ini tidak diperlukan. Mungkin tidak akan pada saat itu karena C telah distandarisasi dalam bentuk C89.

Jika sudah, itu pasti karena deklarasi implisit . Ini biasanya berarti bahwa orang yang menulis kode lupa #include <stdlib.h>dan penganalisa statis sedang digunakan. Ini bukan solusi terbaik dan ide yang jauh lebih baik untuk menjadi hanya #include <stdlib.h>sebagai gantinya. Inilah beberapa kata dari C89 tentang deklarasi implisit:

Jika ekspresi yang mendahului daftar argumen dalam tanda kurung dalam panggilan fungsi hanya terdiri dari pengidentifikasi, dan jika tidak ada deklarasi yang terlihat untuk pengidentifikasi ini, pengidentifikasi secara implisit dinyatakan persis seperti jika, di blok terdalam yang berisi pemanggilan fungsi, deklarasi

extern int identifier();

muncul.

Tapi itu aneh karena mereka tidak menampilkan hasil dari mallockeduanya, dan mallocdan freeberada di file header yang sama.

Mungkin juga ini hanya kesalahan atau cara untuk memberitahu pembaca bahwa freetidak ada hasil.

SS Anne
sumber
5
Hanya karena sebuah bahasa distandarisasi tidak berarti semua orang secara instan memperbarui rantai alat dan kode mereka agar sesuai dengannya. Masuk akal jika gaya lama "K&R" C bertahan sekitar 8 tahun lagi. Namun, saya setuju bahwa aneh bahwa alat analisis statis akan membutuhkan gips untuk freetetapi tidak untuk malloc.
dan04
4
@ dan04 Anda biasanya menggunakan hasil dari malloc;) Saya bukan penggemar menulis hal-hal seperti (batal) printf (...) untuk menghentikan kompiler meludah peringatan tetapi "harus mengkompilasi tanpa peringatan, bahkan yang bodoh" adalah sesuatu yang terjadi dalam banyak proyek.
richardb