Pertanyaan Apakah saya membuang hasil malloc?


Di pertanyaan ini, seseorang menyarankan dalam komentar bahwa saya harus tidak berikan hasil malloc, i.e.

int *sieve = malloc(sizeof(int) * length);

daripada:

int *sieve = (int *) malloc(sizeof(int) * length);

Mengapa ini terjadi?


2039
2018-03-03 10:13


asal


Jawaban:


Tidak; kamu tidak berikan hasil, karena:

  • Itu tidak perlu, karena void * secara otomatis dan aman dipromosikan ke jenis pointer lain dalam kasus ini.
  • Ini menambah kekacauan pada kode, gips tidak terlalu mudah dibaca (terutama jika jenis pointer panjang).
  • Itu membuat Anda mengulangi diri sendiri, yang umumnya buruk.
  • Ini dapat menyembunyikan kesalahan jika Anda lupa untuk menyertakan <stdlib.h>. Ini dapat menyebabkan crash (atau, lebih buruk lagi, tidak menyebabkan tabrakan hingga kemudian di beberapa bagian kode yang benar-benar berbeda). Pertimbangkan apa yang terjadi jika pointer dan bilangan bulat berbeda ukuran; lalu Anda menyembunyikan peringatan dengan mentransmisi dan mungkin kehilangan sedikit alamat yang dikembalikan. Catatan: karena fungsi implisit C11 hilang dari C, dan titik ini tidak lagi relevan karena tidak ada asumsi otomatis yang mengembalikan fungsi yang tidak dilaporkan int.

Sebagai klarifikasi, perhatikan bahwa saya mengatakan "Anda tidak memilih", bukan "tidak perlu untuk melemparkan ". Menurut pendapat saya, itu adalah kegagalan untuk memasukkan pemain, bahkan jika Anda sudah benar. Tidak ada cukup manfaat untuk melakukannya, tetapi banyak risiko potensial, dan termasuk pemain menunjukkan bahwa Anda tidak tahu tentang risiko.

Juga perhatikan, sebagai komentator menunjukkan, bahwa pembicaraan di atas tentang C lurus, bukan C + +. Saya sangat yakin pada C dan C ++ sebagai bahasa yang terpisah.

Untuk menambahkan lebih lanjut, kode Anda tidak perlu mengulangi jenis informasi (int) yang dapat menyebabkan kesalahan. Lebih baik untuk mengalihkan pointer yang digunakan untuk menyimpan nilai kembalian, untuk "mengunci" keduanya bersama-sama:

int *sieve = malloc(length * sizeof *sieve);

Ini juga memindahkan length ke depan untuk meningkatkan visibilitas, dan menjatuhkan tanda kurung yang berlebihan sizeof; mereka hanya dibutuhkan ketika argumennya adalah nama jenis. Banyak orang tampaknya tidak tahu (atau mengabaikan) ini, yang membuat kode mereka lebih verbose. Ingat: sizeof bukan fungsi! :)


Sambil bergerak length ke depan mungkin meningkatkan visibilitas dalam beberapa kasus yang jarang terjadi, kita juga harus memperhatikan bahwa dalam kasus umum, seharusnya lebih baik untuk menulis ekspresi sebagai:

int *sieve = malloc(sizeof *sieve * length);

Sejak menjaga sizeof pertama, dalam hal ini, memastikan perkalian dilakukan setidaknya size_t matematika.

Membandingkan: malloc(sizeof *sieve * length * width) vs. malloc(length * width * sizeof *sieve) yang kedua mungkin meluap length * width kapan width dan length lebih kecil dari jenis size_t.


1915
2018-03-03 10:17



Dalam C, Anda tidak perlu memberikan nilai kembalian malloc. Pointer untuk membatalkan dikembalikan oleh malloc secara otomatis dikonversi ke jenis yang benar. Namun, jika Anda ingin mengkompilasi kode Anda dengan compiler C ++, diperlukan cast. Alternatif yang lebih disukai di antara komunitas adalah menggunakan yang berikut:

int *sieve = malloc(sizeof *sieve * length);

yang juga membebaskan Anda dari keharusan untuk khawatir tentang mengubah sisi kanan ekspresi jika Anda pernah mengubah jenisnya sieve.

Pemain buruk, seperti yang ditunjukkan oleh orang-orang. Khusus pointer gips.


327
2018-03-03 10:17



Kamu melakukan cor, karena:

  • Itu membuat kode Anda lebih portabel antara C dan C ++, dan seperti yang ditunjukkan oleh pengalaman SO, banyak sekali pemrogram mengklaim mereka menulis dalam C ketika mereka benar-benar menulis dalam C ++ (atau C plus ekstensi kompiler lokal).
  • Gagal melakukannya dapat menyembunyikan kesalahan: perhatikan semua contoh SO yang membingungkan saat menulis type * melawan type **.
  • Gagasan bahwa itu membuat Anda tidak memperhatikan Anda gagal #include file header yang sesuai rindu hutan untuk pepohonan. Ini sama dengan mengatakan "jangan khawatir tentang fakta Anda gagal meminta kompiler untuk mengeluh tentang tidak melihat prototipe - stdlib.h sial itu adalah hal penting yang harus diingat!"
  • Ini memaksa sebuah pemeriksaan lintas kognitif ekstra. Ini menempatkan (dugaan) jenis yang diinginkan tepat di sebelah aritmatika yang Anda lakukan untuk ukuran mentah dari variabel itu. Saya yakin Anda bisa melakukan studi SO yang menunjukkan hal itu malloc() bug ditangkap lebih cepat ketika ada gips. Seperti halnya pernyataan, anotasi yang mengungkapkan niat mengurangi bug.
  • Mengulangi diri Anda sendiri dengan cara yang dapat diperiksa oleh mesin sering kali adalah a besar ide. Sebenarnya, itulah pernyataan, dan penggunaan cast ini adalah pernyataan. Asersi masih merupakan teknik paling umum yang kita miliki untuk mendapatkan kode yang benar, karena Turing mendapatkan gagasan itu beberapa tahun yang lalu.

291
2018-02-14 16:15



Seperti yang dinyatakan lain, itu tidak diperlukan untuk C, tetapi untuk C ++. Jika Anda berpikir Anda akan mengkompilasi kode C Anda dengan compiler C ++, yang alasannya pernah, Anda dapat menggunakan makro sebagai gantinya, seperti:

#ifdef __cplusplus
# define NEW(type, count) ((type *)calloc(count, sizeof(type)))
#else
# define NEW(type, count) (calloc(count, sizeof(type)))
#endif

Dengan begitu Anda masih bisa menulisnya dengan cara yang sangat ringkas:

int *sieve = NEW(int, 1);

dan itu akan mengkompilasi untuk C dan C ++.


148
2018-03-03 11:17



Dari Wikipedia

Keuntungan untuk casting

  • Termasuk pemeran dapat memungkinkan program C atau fungsi untuk dikompilasi sebagai C ++.

  • Para pemain memungkinkan untuk versi pra-1989 malloc yang awalnya mengembalikan karakter *.

  • Pengecoran dapat membantu pengembang mengidentifikasi ketidakkonsistenan dalam ukuran jenis jika jenis penunjuk tujuan berubah, terutama jika penunjuk dinyatakan jauh dari panggilan malloc () (meskipun kompiler modern dan analisis statis dapat memperingatkan perilaku tersebut tanpa memerlukan gips).

Kerugian untuk casting

  • Di bawah standar ANSI C, para pemain itu berlebihan.

  • Menambahkan gips dapat menutupi kegagalan untuk menyertakan tajuk stdlib.h, di   dimana prototipe untuk malloc ditemukan. Dengan tidak adanya   prototipe untuk malloc, standar mengharuskan kompiler C.   asumsikan malloc mengembalikan sebuah int. Jika tidak ada pemain, peringatannya adalah   dikeluarkan ketika integer ini ditugaskan ke pointer; Namun, dengan   para pemain, peringatan ini tidak diproduksi, menyembunyikan bug. Pasti   arsitektur dan model data (seperti LP64 pada sistem 64-bit, di mana   panjang dan pointer adalah 64-bit dan int adalah 32-bit), kesalahan ini bisa   sebenarnya menghasilkan perilaku tidak terdefinisi, seperti yang dinyatakan secara implisit   malloc mengembalikan nilai 32-bit sedangkan fungsi yang sebenarnya didefinisikan   mengembalikan nilai 64-bit. Tergantung pada konvensi pemanggilan dan memori   tata letak, ini dapat menyebabkan tumpukan smashing. Masalah ini kecil kemungkinannya   untuk tidak diperhatikan dalam kompiler modern, karena mereka menghasilkan seragam   peringatan bahwa fungsi yang tidak diumumkan telah digunakan, jadi akan ada peringatan   masih muncul. Sebagai contoh, perilaku default GCC adalah menampilkan a   peringatan yang berbunyi "deklarasi implisit tidak kompatibel dari built-in   berfungsi "terlepas dari apakah pemeran ada atau tidak.

  • Jika jenis penunjuk diubah pada deklarasinya, seseorang dapat   juga, perlu mengubah semua garis di mana malloc dipanggil dan dilemparkan.

Meskipun malloc tanpa casting adalah metode yang disukai dan programmer yang paling berpengalaman memilihnya, Anda harus menggunakan apa pun yang Anda sukai dari masalah tersebut.

yaitu: Jika Anda perlu mengkompilasi program C sebagai C ++ (Meskipun itu adalah bahasa yang terpisah), Anda harus menggunakannya malloc dengan casting.


95
2017-10-09 21:23



Dalam C Anda dapat secara implisit mengubah pointer kosong ke jenis pointer lain, jadi cast tidak diperlukan. Menggunakan satu dapat menyarankan kepada pengamat biasa bahwa ada beberapa alasan mengapa diperlukan, yang dapat menyesatkan.


94
2018-03-03 10:18



Anda tidak memberikan hasil malloc, karena hal itu menambah kekacauan pada kode Anda.

Alasan paling umum mengapa orang membuang hasil malloc adalah karena mereka tidak yakin tentang bagaimana bahasa C bekerja. Itu adalah tanda peringatan: jika Anda tidak tahu bagaimana mekanisme bahasa tertentu bekerja, maka tidak coba tebak. Lihat atau tanyakan pada Stack Overflow.

Beberapa komentar:

  • Penunjuk hampa dapat dikonversi ke / dari jenis penunjuk lain tanpa gips eksplisit (C11 6.3.2.3 dan 6.5.16.1).

  • Akan tetapi, C ++ tidak akan mengijinkan sebuah gips implisit void* dan jenis pointer lain. Jadi di C ++, para pemain akan benar. Tetapi jika Anda memprogram dalam C ++, Anda harus menggunakannya new dan bukan malloc (). Dan Anda tidak boleh mengkompilasi kode C menggunakan kompiler C ++.

    Jika Anda perlu mendukung C dan C ++ dengan kode sumber yang sama, gunakan switch kompilator untuk menandai perbedaan. Jangan mencoba menyamakan kedua standar bahasa dengan kode yang sama, karena mereka tidak kompatibel.

  • Jika kompiler C tidak dapat menemukan fungsi karena Anda lupa untuk menyertakan header, Anda akan mendapatkan kesalahan kompiler / linker tentang itu. Jadi jika Anda lupa memasukkan <stdlib.h> itu bukan masalah besar, Anda tidak akan bisa membangun program Anda.

  • Pada kompiler kuno yang mengikuti versi standar yang lebih dari 25 tahun, lupa untuk disertakan <stdlib.h> akan menghasilkan perilaku berbahaya. Karena dalam standar kuno itu, fungsi tanpa prototipe yang terlihat secara implisit mengubah jenis kembalinya menjadi int. Casting hasil dari malloc secara eksplisit akan menyembunyikan bug ini.

    Tapi itu tidak masalah. Anda tidak menggunakan komputer berusia 25 tahun, jadi mengapa Anda menggunakan compiler 25 tahun?


83
2018-03-20 15:53



Di C Anda mendapatkan konversi implisit dari void* ke pointer (data) lainnya.


82
2018-03-03 10:16