Apakah saya menggunakan hasil malloc?

2408

Dalam pertanyaan ini , seseorang menyarankan dalam komentar bahwa saya tidak boleh memberikan hasil malloc, yaitu

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

daripada:

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

Mengapa demikian?

Patrick McDonald
sumber
222
Juga, lebih mudah untuk menulis saringan = malloc (sizeof * sieve * length);
William Pursell
3
Jawabannya di sini adalah ladang ranjau satu sisi. Jawabannya adalah, tergantung". Bukan hal yang penting untuk membuat program bekerja. Namun beberapa standar pengkodean memerlukannya ... Sebagai contoh, lihat Standar Penyandian CERT C
Dr. Person Person II
Anehnya, semua orang setuju bahwa Anda tidak berperan NULL. (itu mungkin mengapa C ++ diperkenalkan nullptr: C ++ tidak mengizinkan cast pointer implisit)
Sapphire_Brick
Anda bisa, tetapi Anda tidak perlu melakukannya. Tetapi Anda perlu di C ++.
user12211554

Jawaban:

2217

Tidak ada ; Anda tidak memberikan hasilnya, karena:

  • Tidak perlu, seperti void *yang dipromosikan secara otomatis dan aman ke jenis penunjuk lain dalam kasus ini.
  • Ini menambah kekacauan pada kode, gips tidak mudah dibaca (terutama jika tipe pointer panjang).
  • Itu membuat Anda mengulangi sendiri, yang umumnya buruk.
  • Itu dapat menyembunyikan kesalahan jika Anda lupa untuk memasukkan <stdlib.h>. Ini dapat menyebabkan crash (atau, lebih buruk lagi, tidak menyebabkan crash sampai nanti di beberapa bagian kode yang sama sekali berbeda). Pertimbangkan apa yang terjadi jika pointer dan bilangan bulat berukuran berbeda; maka Anda menyembunyikan peringatan dengan melemparkan dan mungkin kehilangan bit alamat Anda yang dikembalikan. Catatan: sejak C99 fungsi implisit hilang dari C, dan titik ini tidak lagi relevan karena tidak ada asumsi otomatis bahwa fungsi yang dideklarasikan kembali int.

Sebagai klarifikasi, perhatikan bahwa saya mengatakan "Anda tidak menggunakan", bukan "Anda tidak perlu menggunakan". Menurut pendapat saya, gagal memasukkan para pemeran, bahkan jika Anda melakukannya dengan benar. Tidak ada manfaat untuk melakukannya, tetapi banyak risiko potensial, dan termasuk para pemain menunjukkan bahwa Anda tidak tahu tentang risikonya.

Perhatikan juga, sebagaimana ditunjukkan oleh komentator, bahwa pembicaraan di atas tentang straight C, bukan C ++. Saya sangat percaya pada C dan C ++ sebagai bahasa yang terpisah.

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

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

Ini juga memindahkan lengthke depan untuk meningkatkan visibilitas, dan menjatuhkan tanda kurung yang berlebihan dengan sizeof; mereka hanya diperlukan ketika argumennya adalah nama ketik. Banyak orang tampaknya tidak tahu (atau mengabaikan) ini, yang membuat kode mereka lebih bertele-tele. Ingat: sizeofbukan fungsi! :)


Sementara bergerak lengthke depan dapat meningkatkan visibilitas dalam beberapa kasus yang jarang terjadi, kita juga harus memperhatikan bahwa dalam kasus umum, sebaiknya menulis ekspresi sebagai:

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

Karena menjaga yang sizeofpertama, dalam hal ini, memastikan perkalian dilakukan dengan setidaknya size_tmatematika.

Bandingkan: malloc(sizeof *sieve * length * width)vs. malloc(length * width * sizeof *sieve)yang kedua dapat meluap length * widthketika widthdan lengthjenis lebih kecil dari size_t.

beristirahat
sumber
21
Silakan pertimbangkan untuk memperbarui jawabannya. Para pemain tidak lagi berbahaya, dan mengulangi diri sendiri tidak selalu merupakan hal yang buruk (redundansi dapat membantu menangkap kesalahan).
n. 'kata ganti' m.
11
Kompiler telah berubah. Kompiler terbaru akan memperingatkan Anda tentang deklarasi malloc yang hilang.
n. 'kata ganti' m.
55
@nm ok. Saya pikir itu buruk untuk mengasumsikan bahwa siapa pun yang membaca di sini memiliki kompiler tertentu. Juga, karena C11 seluruh konsep "fungsi implisit" hilang, saya tidak tahu itu. Meski begitu, saya tidak melihat gunanya menambahkan pemain tidak berguna. Apakah Anda juga melakukan int x = (int) 12;hanya untuk memperjelas?
bersantai
22
@ nm jika secara eksplisit casting void pointer "membantu" menyelesaikan bug, Anda lebih mungkin menemukan perilaku tidak terdefinisi, yang berarti program tersebut kemungkinan memiliki bug yang jauh lebih buruk, belum ditemukan yang belum Anda temui. Dan suatu hari, pada malam musim dingin yang dingin, Anda akan pulang kerja untuk menemukan halaman GitHub Anda dibanjiri dengan laporan masalah yang mengeluhkan setan yang terbang keluar dari hidung pengguna
Braden Best
12
@wwind Bahkan saya setuju dengan Anda, (int)12tidak sebanding. 12 adalah sebuah int, pemain tidak hanya apa-apa. Retval dari malloc()adalah void *, bukan tipe pointer dilemparkan ke. (Jika tidak void *. Jadi analoginya (int)12adalah (void*)malloc(…)apa yang tidak didiskusikan oleh siapa pun.)
Amin Negm-Awad
376

Di C, Anda tidak perlu memberikan nilai balik dari malloc. Pointer untuk membatalkan dikembalikan oleh mallocsecara otomatis dikonversi ke tipe yang benar. Namun, jika Anda ingin kode Anda dikompilasi dengan kompiler C ++, dibutuhkan pemeran. Alternatif yang disukai di antara masyarakat adalah menggunakan yang berikut ini:

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

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

Gips buruk, seperti yang ditunjukkan orang. Terutama gips pointer.

secara langsung
sumber
71
@ MAKZ Saya berpendapat bahwa malloc(length * sizeof *sieve)membuatnya terlihat seperti sizeofvariabel - jadi saya pikir malloc(length * sizeof(*sieve))lebih mudah dibaca.
Michael Anderson
21
Dan malloc(length * (sizeof *sieve))masih lebih mudah dibaca. MENURUT OPINI SAYA.
Toby Speight
19
@Michael Anderson ()mengeluarkan masalah, perhatikan bahwa gaya yang disarankan Anda mengubah urutan., Pertimbangkan ketika jumlah elemen dihitung seperti length*width, menjaga yang sizeofpertama dalam hal ini memastikan perkalian dilakukan dengan setidaknya size_tmatematika. Bandingkan malloc(sizeof( *ptr) * length * width)vs. malloc(length * width * sizeof (*ptr))- yang ke-2 bisa meluap length*widthketika width,lengthjenis yang lebih kecil itu size_t.
chux - Reinstate Monica
3
@ chux tidak jelas, tetapi jawabannya telah diedit sehingga komentar saya kurang relevan - saran aslinya adalahmalloc(sizeof *sieve * length)
Michael Anderson
12
C bukan C ++. Berpura-pura bahwa mereka pada akhirnya akan menyebabkan kebingungan dan kesedihan. Jika Anda menggunakan C ++, maka cast gaya-C juga buruk (kecuali Anda menggunakan kompiler C ++ yang sangat lama). Dan static_cast>()(atau reinterpret_cast<>()) tidak kompatibel dengan dialek C.
David C.
349

Anda melakukan casting, karena:

  • Itu membuat kode Anda lebih portabel antara C dan C ++, dan seperti yang ditunjukkan oleh pengalaman SO, banyak programmer mengklaim bahwa 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 kapan harus menulis type *versus type **.
  • Gagasan bahwa itu membuat Anda memperhatikan Anda gagal ke #includefile header yang sesuai melewatkan hutan untuk pohon . Itu sama dengan mengatakan "jangan khawatir tentang fakta Anda gagal meminta kompiler mengeluh tentang tidak melihat prototipe - bahwa stdlib.h sial adalah hal yang NYATA penting untuk diingat!"
  • Ini memaksa pemeriksaan silang kognitif ekstra . Ini menempatkan (dugaan) jenis yang diinginkan tepat di sebelah aritmatika yang Anda lakukan untuk ukuran mentah variabel itu. Saya yakin Anda bisa melakukan studi SO yang menunjukkan bahwa malloc()bug ditangkap lebih cepat ketika ada pemain. Seperti halnya pernyataan, anotasi yang mengungkapkan niat mengurangi bug.
  • Mengulangi diri Anda sedemikian rupa sehingga mesin dapat memeriksa seringkali merupakan ide bagus . Sebenarnya, itulah yang menjadi penegasan, dan penggunaan pemeran ini sebagai penegasan. Pernyataan masih merupakan teknik paling umum yang kami miliki untuk mendapatkan kode yang benar, karena Turing muncul dengan ide bertahun-tahun yang lalu.
Ron Burk
sumber
39
@ulidtko Jika Anda tidak tahu, mungkin untuk menulis kode yang mengkompilasi C dan C ++. Sebenarnya sebagian besar file header seperti ini, dan mereka sering berisi kode (fungsi makro dan inline). Memiliki .c/ .cppfile untuk dikompilasi karena keduanya tidak sering sangat berguna, tetapi satu kasus menambahkan throwdukungan C ++ ketika dikompilasi dengan kompiler C ++ (tetapi return -1;ketika dikompilasi dengan kompiler C, atau apa pun).
hyde
37
Jika seseorang memiliki panggilan malloc sebaris di tajuk saya tidak akan terkesan, #ifdef __cplusplus dan extern "C" {} untuk pekerjaan ini, bukan menambahkan gips tambahan.
paulm
15
Nah, poin 1 tidak relevan, karena C! = C ++, poin lainnya juga sepele, jika Anda menggunakan variabel dalam mallocpanggilan Anda : char **foo = malloc(3*sizeof(*foo));jika cukup bukti: 3 pointer ke char pointer. kemudian loop, dan lakukan foo[i] = calloc(101, sizeof(*(foo[i])));. Alokasikan array 101 karakter, yang diinisialisasi dengan rapi ke nol. Tidak dibutuhkan pemeran. ubah deklarasi menjadi unsigned charatau tipe apa pun, dan Anda masih bagus
Elias Van Ootegem
34
Ketika saya pikir saya mendapatkannya, itu dia! Jawaban yang fantastis. Ini pertama kalinya di sini di StackOverflow bahwa saya memberi +1 dua jawaban yang berlawanan! +1 Tidak, Anda tidak melakukan casting, dan +1 Ya, Anda melakukan casting! LOL. Kalian luar biasa. Dan untuk saya dan murid-murid saya, saya membuat keputusan: Saya berperan. Jenis kesalahan yang dilakukan siswa lebih mudah terlihat saat casting.
Dr Beco
15
@Leushenko: Mengulangi diri Anda dengan cara yang tidak dapat divalidasi oleh mesin atau inspeksi lokal tidak baik. Mengulangi diri Anda dengan cara yang bisa divalidasi dengan cara seperti itu tidak terlalu buruk. Mengingat struct Zebra *p; ... p=malloc(sizeof struct Zebra);, malloc tidak dapat menghindari duplikasi informasi tentang tipe p, tetapi baik kompiler maupun inspeksi kode lokal tidak akan mendeteksi masalah jika satu tipe berubah tetapi yang lain tidak. Ubah kode ke p=(struct Zebra*)malloc(sizeof struct Zebra);dan kompiler akan mengomel jika tipe pemain tidak cocok p, dan inspeksi lokal akan mengungkapkan ...
supercat
170

Seperti yang dinyatakan orang lain, itu tidak diperlukan untuk C, tetapi diperlukan untuk C ++. Jika Anda berpikir Anda akan mengkompilasi kode C Anda dengan kompiler C ++, untuk alasan apa pun, Anda dapat menggunakan makro, 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 dikompilasi untuk C dan C ++.

quinmars
sumber
17
Karena Anda tetap menggunakan makro, mengapa Anda tidak menggunakan newdefinisi C ++?
Hosam Aly
63
Karena tidak ada alasan untuk melakukannya. Ini terutama untuk program C yang dikompilasi dengan kompiler C ++. Jika Anda akan menggunakan 'baru', satu-satunya hal yang Anda dapatkan adalah masalah. Anda perlu juga makro secara gratis. Dan Anda perlu makro untuk membebaskan array, diferensiasi yang tidak ada dalam C.
quinmars
8
Belum lagi jika bukan Anda yang membebaskan memori tapi mungkin perpustakaan C yang Anda gunakan, dll. Banyak masalah yang mungkin terjadi tanpa keuntungan apa pun.
quinmars
86
@ Husam: Ya, tentu saja. Jika Anda menggunakan newAnda harus menggunakan deletedan jika Anda menggunakan malloc()Anda harus Anda free(). Jangan pernah mencampurnya.
Graeme Perrow
17
Jika seseorang akan mengambil pendekatan ini, memanggil makro NEWmungkin adalah ide yang buruk karena sumber daya tidak pernah dikembalikan menggunakan delete(atau DELETE) sehingga Anda mencampur kosakata Anda. Sebaliknya, memberi nama MALLOC, atau lebih tepatnya CALLOCdalam hal ini, akan lebih masuk akal.
mah
139

Dari Wikipedia :

Keuntungan untuk casting

  • Termasuk para pemain memungkinkan program C atau fungsi untuk dikompilasi sebagai C ++.

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

  • Casting dapat membantu pengembang mengidentifikasi ketidakkonsistenan dalam ukuran jenis jika tipe pointer tujuan berubah, terutama jika pointer dinyatakan jauh dari panggilan malloc () (meskipun kompiler modern dan penganalisa statis dapat memperingatkan perilaku seperti itu tanpa memerlukan pemeran).

Kekurangan untuk casting

  • Di bawah standar ANSI C, gips tidak diperlukan.

  • Menambahkan gips dapat menutupi kegagalan untuk menyertakan header stdlib.h, di mana prototipe untuk malloc ditemukan. Dengan tidak adanya prototipe untuk malloc, standar mensyaratkan bahwa kompiler C menganggap malloc mengembalikan int. Jika tidak ada pemeran, peringatan dikeluarkan ketika bilangan bulat ini ditugaskan ke pointer; Namun, dengan para pemain, peringatan ini tidak dihasilkan, menyembunyikan bug. Pada arsitektur dan model data tertentu (seperti LP64 pada sistem 64-bit, di mana panjang dan pointer adalah 64-bit dan int adalah 32-bit), kesalahan ini sebenarnya dapat mengakibatkan perilaku tidak terdefinisi, karena malloc yang dinyatakan secara implisit mengembalikan 32- nilai bit sedangkan fungsi sebenarnya didefinisikan mengembalikan nilai 64-bit. Bergantung pada konvensi panggilan dan tata letak memori, ini dapat menyebabkan stack smashing. Masalah ini cenderung tidak diperhatikan dalam kompiler modern, karena mereka secara seragam menghasilkan peringatan bahwa fungsi yang tidak dideklarasikan telah digunakan, sehingga peringatan akan tetap muncul. Misalnya, perilaku default GCC adalah menampilkan peringatan yang bertuliskan "deklarasi implisit fungsi bawaan yang tidak kompatibel" terlepas dari apakah pemeran hadir atau tidak.

  • Jika jenis pointer diubah pada deklarasi, seseorang mungkin juga perlu mengubah semua baris tempat malloc dipanggil dan dilemparkan.

Meskipun malloc tanpa casting adalah metode yang disukai dan pemrogram yang paling berpengalaman memilihnya , Anda harus menggunakan mana pun yang Anda suka memiliki masalah.

yaitu: Jika Anda perlu mengkompilasi program C sebagai C ++ (Meskipun itu adalah bahasa yang terpisah) Anda harus memberikan hasil penggunaan malloc.

ashiquzzaman33
sumber
1
Apa artinya " Casting dapat membantu pengembang mengidentifikasi ketidakkonsistenan dalam ukuran jenis jika tipe pointer tujuan berubah, terutama jika pointer dinyatakan jauh dari malloc()panggilan " artinya? Bisakah Anda memberi contoh?
Spikatrix
3
@CoolGuy: Lihat komentar sebelumnya tentang jawaban lain . Tetapi perhatikan bahwa p = malloc(sizeof(*p) * count)idiom tersebut mengambil perubahan dalam tipe secara otomatis, jadi Anda tidak perlu mendapatkan peringatan dan mengubah apa pun. Jadi ini bukan keuntungan nyata vs alternatif terbaik untuk tidak casting.
Peter Cordes
7
Ini adalah jawaban yang tepat: Ada pro dan kontra, dan itu bermuara pada selera (kecuali kode harus dikompilasi sebagai C ++ - maka para pemain wajib).
Peter - Reinstate Monica
3
Poin 3 sedang diperdebatkan, karena Jika jenis pointer diubah pada deklarasi, seseorang harus memeriksa setiap instance dari malloc, realloc dan bebas memasukkan jenis itu. Casting akan memaksa Anda untuk melakukan hal itu.
Michaël Roy
104

Dalam C Anda secara implisit dapat mengkonversi voidpointer ke jenis pointer lain, jadi gips tidak diperlukan. Menggunakan satu dapat menyarankan kepada pengamat biasa bahwa ada beberapa alasan mengapa seseorang diperlukan, yang mungkin menyesatkan.

PaulJWilliams
sumber
100

Anda tidak melemparkan hasil malloc, karena hal itu menambah kekacauan yang tidak berguna ke kode Anda.

Alasan paling umum mengapa orang melemparkan hasil malloc adalah karena mereka tidak yakin tentang bagaimana bahasa C bekerja. Itu tanda peringatan: jika Anda tidak tahu bagaimana mekanisme bahasa tertentu bekerja, maka jangan menebak. Cari atau tanyakan di Stack Overflow.

Beberapa komentar:

  • Pointer void dapat dikonversi ke / dari tipe pointer lainnya tanpa cast eksplisit (C11 6.3.2.3 dan 6.5.16.1).

  • Namun C ++ tidak akan mengizinkan cast implisit antara void*dan tipe pointer lain. Jadi di C ++, para pemain akan benar. Tetapi jika Anda memprogram dalam C ++, Anda harus menggunakan newdan 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 sakelar kompiler untuk menandai perbedaannya. Jangan mencoba untuk memuaskan kedua standar bahasa dengan kode yang sama, karena keduanya tidak kompatibel.

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

  • Pada kompiler kuno yang mengikuti versi standar yang berusia lebih dari 25 tahun, lupa memasukkan <stdlib.h>akan menghasilkan perilaku berbahaya. Karena dalam standar kuno itu, fungsi tanpa prototipe yang terlihat secara implisit mengkonversi tipe kembali ke int. Casting hasil dari malloc secara eksplisit akan menyembunyikan bug ini.

    Tapi itu benar-benar bukan masalah. Anda tidak menggunakan komputer berusia 25 tahun, jadi mengapa Anda menggunakan kompiler berusia 25 tahun?

Lundin
sumber
9
"Kerancuan tanpa tujuan" adalah hiperbola penolakan yang cenderung menggagalkan kemungkinan meyakinkan siapa pun yang belum setuju dengan Anda. Para pemain tentu saja tidak ada gunanya; Jawaban Ron Burk dan Kaz membuat argumen yang mendukung casting yang sangat saya setujui. Apakah kekhawatiran itu memiliki bobot lebih dari kekhawatiran yang Anda sebutkan adalah pertanyaan yang wajar untuk ditanyakan. Bagi saya, kekhawatiran Anda terlihat relatif kecil dibandingkan dengan mereka.
Don Hatch
"Void pointer dapat dikonversi ke / dari tipe pointer lain tanpa gips eksplisit" tidak didukung oleh 6.3.2.3. Mungkin Anda berpikir tentang "pointer ke semua jenis objek"? "void pointer" dan "pointer ke suatu fungsi" tidak begitu mudah dikonversi.
chux - Reinstate Monica
Memang referensi itu tidak lengkap. Bagian yang relevan untuk "saksi" adalah aturan penugasan sederhana 6.5.16.1. + msgstr "satu operan adalah pointer ke tipe objek, dan yang lainnya adalah pointer ke versi void yang berkualitas atau tidak memenuhi syarat". Saya telah menambahkan referensi ini ke jawaban untuk kelengkapan.
Lundin
91

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

EFRAIM
sumber
6
@ Jen: Oke, mungkin kata yang lebih tepat adalah "konversi implisit". Seperti penggunaan variabel integral dalam ekspresi floating point.
EFraim
@ Evraim Itu benar-benar akan menghasilkan gips, dan yang implisit pada saat itu
Fisikawan Gila
71

Menempatkan nilai yang dikembalikan malloc()tidak perlu sekarang, tapi saya ingin menambahkan satu poin yang sepertinya tidak ada yang menunjukkan:

Pada zaman kuno, yaitu, sebelum ANSI C menyediakan void *sebagai jenis pointer umum, char *adalah jenis untuk penggunaan tersebut. Dalam hal ini, para pemain dapat mematikan peringatan kompiler.

Referensi: C FAQ

Yu Hao
sumber
2
Mematikan peringatan kompiler adalah ide yang buruk.
Albert van der Horst
8
@AlbertvanderHorst Tidak jika Anda melakukannya dengan memecahkan masalah yang tepat peringatan itu ada untuk memperingatkan Anda.
Dan Bechard
@Dan. Jika dengan menyelesaikan masalah yang tepat berarti menulis ulang subrutin untuk mengembalikan tipe ANSI C modern, bukan karakter *, saya setuju. Saya tidak akan menyebut itu mematikan kompiler. Jangan menyerah kepada manajer yang bersikeras bahwa tidak ada peringatan kompiler, alih-alih menggunakannya pada setiap kompilasi untuk menemukan kemungkinan masalah. Groetjes Albert
Albert van der Horst
53

Hanya menambahkan pengalaman saya, belajar teknik komputer saya melihat bahwa dua atau tiga profesor yang saya lihat menulis di C selalu melemparkan malloc, namun yang saya tanyakan (dengan CV yang sangat besar dan pemahaman tentang C) mengatakan kepada saya bahwa itu sama sekali tidak perlu tetapi hanya digunakan untuk benar-benar spesifik, dan untuk membuat siswa masuk ke mentalitas menjadi sangat spesifik. Pada dasarnya casting tidak akan mengubah apa pun dalam cara kerjanya, ia melakukan persis apa yang dikatakannya, mengalokasikan memori, dan casting tidak berpengaruh, Anda mendapatkan memori yang sama, dan bahkan jika Anda melemparkannya ke sesuatu yang lain secara tidak sengaja (dan entah bagaimana menghindari kompiler kesalahan) C akan mengaksesnya dengan cara yang sama.

Sunting: Casting memiliki poin tertentu. Ketika Anda menggunakan notasi array, kode yang dihasilkan harus tahu berapa banyak tempat memori yang harus dimajukan untuk mencapai awal elemen berikutnya, ini dicapai melalui casting. Dengan cara ini Anda tahu bahwa untuk double Anda pergi 8 byte ke depan sementara untuk int Anda pergi 4, dan seterusnya. Dengan demikian itu tidak berpengaruh jika Anda menggunakan notasi pointer, dalam notasi array menjadi perlu.

pengguna3079666
sumber
3
Kecuali seperti yang telah disebutkan, para pemain mungkin menyembunyikan bug dan membuat kode lebih sulit untuk dianalisis untuk kompiler atau penganalisa statis.
Lundin
2
"Pada dasarnya casting tidak akan mengubah apa pun dalam cara kerjanya". Casting ke tipe yang cocok seharusnya tidak mengubah apa pun, tetapi haruskah tipe var berubah dan para pemain tidak lagi cocok, bisakah masalah muncul? IWOs, jenis gips dan var harus tetap sinkron - dua kali pekerjaan pemeliharaan.
chux - Reinstate Monica
Saya bisa melihat mengapa Prof lebih suka casting. Casting mungkin berguna dari sudut pandang pendidikan di mana ia menyampaikan informasi instruktur dan kode siswa tidak perlu dipertahankan - kode membuangnya. Namun dari perspektif pengkodean, peer-review, dan pemeliharaan , p = malloc(sizeof *p * n);sangat sederhana dan lebih baik.
chux - Reinstate Monica
53

Itu tidak wajib untuk melemparkan hasil malloc, karena itu kembali void*, dan void*dapat diarahkan ke tipe data apa pun.

pengguna968000
sumber
34

Pointer void adalah pointer objek generik dan C mendukung konversi implisit dari tipe pointer kosong ke tipe lain, jadi tidak perlu secara eksplisit mengetiknya.

Namun, jika Anda ingin kode yang sama bekerja dengan sempurna pada platform C ++, yang tidak mendukung konversi implisit, Anda perlu melakukan typecasting, jadi semuanya tergantung pada kegunaan.

Berusaha keras
sumber
2
Ini bukan kasus penggunaan normal untuk mengkompilasi sumber tunggal sebagai C dan C ++ (sebagai lawan, katakanlah, menggunakan file header yang berisi deklarasi untuk menghubungkan kode C dan C ++ bersama-sama). Menggunakan mallocdan berteman di C ++ adalah tanda peringatan yang baik yang layak mendapatkan perhatian khusus (atau menulis ulang dalam C).
Toby Speight
1
"Sebuah penunjuk kosong adalah penunjuk generik" -> "Penunjuk kosong adalah penunjuk objek generik ". Ukuran pointer fungsi dapat melebihi void *, sehingga void *tidak cukup untuk menyimpan pointer fungsi dengan baik.
chux - Reinstate Monica
Niat saya pada baris itu tetap sama tapi terima kasih @ chux untuk sarannya
Endeavour
33

Ini adalah apa yang dikatakan oleh manual Referensi Perpustakaan GNU :

Anda dapat menyimpan hasil mallocke dalam variabel penunjuk apa pun tanpa gips, karena ISO C secara otomatis mengkonversi tipe void *ke tipe penunjuk lain bila perlu. Tetapi para pemain diperlukan dalam konteks selain operator penugasan atau jika Anda ingin kode Anda dijalankan dalam C. tradisional

Dan memang standar ISO C11 (hal 347) mengatakan demikian:

Pointer kembali jika alokasi berhasil selaras sehingga dapat ditugaskan untuk pointer ke semua jenis objek dengan persyaratan penyelarasan mendasar dan kemudian digunakan untuk mengakses objek atau array objek tersebut di ruang yang dialokasikan (sampai ruang secara eksplisit dialokasikan)

Slothworks
sumber
31

Jenis yang dikembalikan adalah void *, yang dapat dilemparkan ke tipe data pointer yang diinginkan agar dapat di-dereferensi.

swap
sumber
1
void* dapat dilemparkan ke jenis yang diinginkan, tetapi tidak perlu melakukannya karena akan dikonversi secara otomatis. Jadi para pemain tidak perlu, dan pada kenyataannya tidak diinginkan karena alasan yang disebutkan dalam jawaban skor tinggi.
Toby Speight
tetapi hanya jika Anda perlu melakukan dereferensi "on the fly", jika Anda membuat variabel sebagai gantinya itu akan dikonversi dengan aman dan secara otomatis menjadi tipe efektif variabel, tanpa casting (dalam C).
Ferrarezi
28

Dalam bahasa C, pointer void dapat ditetapkan ke pointer apa pun, itulah sebabnya Anda tidak harus menggunakan tipe cast. Jika Anda ingin alokasi "ketik aman", saya dapat merekomendasikan fungsi makro berikut, yang selalu saya gunakan dalam proyek C saya:

#include <stdlib.h>
#define NEW_ARRAY(ptr, n) (ptr) = malloc((n) * sizeof *(ptr))
#define NEW(ptr) NEW_ARRAY((ptr), 1)

Dengan ini di tempat Anda bisa mengatakan

NEW_ARRAY(sieve, length);

Untuk array non-dinamis, fungsi makro ketiga yang harus dimiliki adalah

#define LEN(arr) (sizeof (arr) / sizeof (arr)[0])

yang membuat loop array lebih aman dan nyaman:

int i, a[100];

for (i = 0; i < LEN(a); i++) {
   ...
}
August Karlstrom
sumber
"pointer kosong dapat ditugaskan ke objek pointer" Pointer fungsi adalah masalah lain, meskipun bukan malloc()satu.
chux
Menetapkan suatu void*ke / dari suatu pointer fungsi dapat kehilangan informasi sehingga "sebuah pointer kosong dapat ditugaskan ke pointer mana saja," adalah masalah dalam kasus-kasus tersebut. Menetapkan a void*, dari malloc() ke penunjuk objek apa pun tidak menjadi masalah.
chux - Reinstate Monica
The doLoop komentar terkait macro melibatkan loop belum yang bertanya-tanya jauh dari pertanyaan judul. Menghapus komentar itu. Akan mengambil yang ini nanti juga.
chux - Reinstate Monica
27

Itu tergantung pada bahasa pemrograman dan kompiler. Jika Anda menggunakan mallocdalam C, tidak perlu mengetikkan cast, karena akan secara otomatis mengetik cast. Namun, jika Anda menggunakan C ++, maka Anda harus mengetikkan cast karena mallocakan mengembalikan sebuah void*tipe.

Jeyamaran
sumber
1
Fungsi malloc mengembalikan pointer kosong di C juga tetapi aturan bahasanya berbeda dari C ++.
August Karlstrom
16

Orang yang terbiasa dengan GCC dan Dentang manja. Tidak terlalu bagus di luar sana.

Saya telah sangat ngeri selama bertahun-tahun oleh kompiler-kompiler yang berumur sangat tua yang harus saya gunakan. Seringkali perusahaan dan manajer mengadopsi pendekatan ultra-konservatif untuk mengganti kompiler dan bahkan tidak akan menguji apakah kompiler baru (dengan kepatuhan standar yang lebih baik dan optimalisasi kode) akan bekerja dalam sistem mereka. Realitas praktis untuk pengembang yang bekerja adalah bahwa ketika Anda membuat kode, Anda harus menutupi basis Anda dan, sayangnya, casting mallocs adalah kebiasaan yang baik jika Anda tidak dapat mengontrol kompiler apa yang mungkin diterapkan pada kode Anda.

Saya juga menyarankan bahwa banyak organisasi menerapkan standar pengkodean mereka sendiri dan bahwa itu harus menjadi metode yang diikuti orang jika sudah ditentukan. Dengan tidak adanya panduan eksplisit saya cenderung pergi untuk kemungkinan besar untuk dikompilasi di mana-mana, daripada kepatuhan terhadap standar.

Argumen bahwa itu tidak perlu di bawah standar saat ini cukup valid. Tetapi argumen itu menghilangkan kepraktisan dunia nyata. Kami tidak membuat kode di dunia yang dikuasai secara eksklusif berdasarkan standar saat itu, tetapi oleh kepraktisan yang saya suka sebut "bidang realitas manajemen lokal". Dan itu bengkok dan memutar lebih dari ruang waktu yang pernah ada. :-)

YMMV.

Saya cenderung menganggap casting malloc sebagai operasi defensif. Tidak cantik, tidak sempurna, tetapi umumnya aman. (Jujur, jika Anda tidak termasuk stdlib.h maka Anda sudah cara lebih banyak masalah daripada pengecoran malloc!).

StephenG
sumber
15

Saya memasang gips hanya untuk menunjukkan ketidaksetujuan lubang jelek di sistem tipe, yang memungkinkan kode seperti cuplikan berikut untuk dikompilasi tanpa diagnostik, meskipun tidak ada gips yang digunakan untuk menghasilkan konversi yang buruk:

double d;
void *p = &d;
int *q = p;

Saya berharap itu tidak ada (dan tidak ada di C ++) dan jadi saya melemparkan. Ini mewakili selera saya, dan politik pemrograman saya. Saya tidak hanya memberikan pointer, tetapi secara efektif, memberikan suara, dan mengusir setan kebodohan . Jika saya tidak bisa benar - benar mengusir kebodohan , maka setidaknya izinkan saya mengungkapkan keinginan untuk melakukannya dengan isyarat protes.

Bahkan, praktik yang baik adalah membungkus malloc(dan teman) dengan fungsi yang kembali unsigned char *, dan pada dasarnya tidak pernah digunakan void *dalam kode Anda. Jika Anda memerlukan penunjuk generik ke objek apa pun, gunakan a char *atau unsigned char *, dan gips ke kedua arah. Satu relaksasi yang bisa dimanjakan, mungkin, adalah menggunakan fungsi suka memsetdan memcpytanpa gips.

Pada topik casting dan kompatibilitas C ++, jika Anda menulis kode Anda sehingga dikompilasi sebagai C dan C ++ (dalam hal ini Anda harus memberikan nilai pengembalian mallocketika menugaskannya ke sesuatu selain void *), Anda dapat melakukan yang sangat membantu hal untuk diri sendiri: Anda dapat menggunakan makro untuk casting yang menerjemahkan ke gaya C ++ saat dikompilasi sebagai C ++, tetapi kurangi menjadi cast C saat mengkompilasi sebagai C:

/* In a header somewhere */
#ifdef __cplusplus
#define strip_qual(TYPE, EXPR) (const_cast<TYPE>(EXPR))
#define convert(TYPE, EXPR) (static_cast<TYPE>(EXPR))
#define coerce(TYPE, EXPR) (reinterpret_cast<TYPE>(EXPR))
#else
#define strip_qual(TYPE, EXPR) ((TYPE) (EXPR))
#define convert(TYPE, EXPR) ((TYPE) (EXPR))
#define coerce(TYPE, EXPR) ((TYPE) (EXPR))
#endif

Jika Anda mematuhi makro ini, maka greppencarian sederhana dari basis kode Anda untuk pengidentifikasi ini akan menunjukkan kepada Anda di mana semua gips Anda, sehingga Anda dapat meninjau apakah ada yang salah.

Kemudian, maju, jika Anda secara teratur mengkompilasi kode dengan C ++, itu akan memberlakukan penggunaan pemain yang sesuai. Misalnya, jika Anda menggunakan strip_qualhanya untuk menghapus a constatau volatile, tetapi program berubah sedemikian rupa sehingga konversi jenis sekarang terlibat, Anda akan mendapatkan diagnostik, dan Anda harus menggunakan kombinasi gips untuk mendapatkan konversi yang diinginkan.

Untuk membantu Anda mematuhi makro ini, kompiler GNU C ++ (bukan C!) Memiliki fitur yang indah: diagnostik opsional yang dibuat untuk semua kejadian cetakan gaya C.

     -Wold-style-cast (khusus C ++ dan Objective-C ++)
         Peringatkan jika gaya lama (gaya-C) digunakan untuk tipe non-void
         dalam program C ++. Gips gaya baru (dynamic_cast,
         static_cast, reinterpret_cast, dan const_cast) kurang rentan
         untuk efek yang tidak diinginkan dan lebih mudah untuk mencari.

Jika kode C Anda dikompilasi sebagai C ++, Anda dapat menggunakan -Wold-style-castopsi ini untuk mengetahui semua kemunculan (type)sintaks casting yang dapat masuk ke dalam kode, dan menindaklanjuti diagnostik ini dengan menggantinya dengan pilihan yang sesuai dari antara makro di atas (atau kombinasi, jika perlu).

Perlakuan konversi ini adalah pembenaran teknis mandiri tunggal terbesar untuk bekerja dalam "Clean C": dialek C dan C ++ gabungan, yang pada gilirannya secara teknis membenarkan penuangan nilai kembali malloc.

Kaz
sumber
Seperti yang ditunjukkan lainnya, saya biasanya akan merekomendasikan untuk tidak mencampur kode C dan C ++. Namun, jika Anda memiliki alasan kuat untuk melakukannya, maka makro mungkin berguna.
Phil1970
@ Phil1970 Semuanya ditulis dalam satu dialek kohesif, yang kebetulan bersifat portabel untuk kompiler C dan C ++, dan memanfaatkan beberapa kemampuan C ++. Semua itu harus dikompilasi sebagai C ++, atau kalau tidak semua dikompilasi sebagai C.
Kaz
Yaitu apa yang saya coba katakan dalam komentar sebelumnya adalah bahwa tidak ada pencampuran C dan C ++. Maksudnya adalah bahwa semua kode dikompilasi sebagai C atau semua dikompilasi sebagai C ++.
Kaz
15

Hal terbaik untuk dilakukan saat memprogram dalam C kapan pun memungkinkan:

  1. Buat program Anda dikompilasi melalui kompiler C dengan semua peringatan diaktifkan -Walldan perbaiki semua kesalahan dan peringatan
  2. Pastikan tidak ada variabel yang dideklarasikan sebagai auto
  3. Kemudian kompilasi menggunakan kompiler C ++ dengan -Walldan -std=c++11. Perbaiki semua kesalahan dan peringatan.
  4. Sekarang kompilasi menggunakan kompiler C lagi. Program Anda sekarang harus dikompilasi tanpa peringatan dan mengandung lebih sedikit bug.

Prosedur ini memungkinkan Anda memanfaatkan pemeriksaan tipe ketat C ++, sehingga mengurangi jumlah bug. Secara khusus, prosedur ini memaksa Anda untuk memasukkan stdlib.hatau Anda akan mendapatkan

malloc tidak dinyatakan dalam lingkup ini

dan juga memaksa Anda untuk melemparkan hasil mallocatau Anda akan dapatkan

konversi tidak valid dari void*keT*

atau apa pun tipe target Anda.

Satu-satunya manfaat dari menulis dalam C daripada C ++ yang dapat saya temukan adalah

  1. C memiliki ABI yang ditentukan dengan baik
  2. C ++ dapat menghasilkan lebih banyak kode [pengecualian, RTTI, templat, runtime polymorphism]

Perhatikan bahwa kontra kedua harus dalam kasus yang ideal menghilang ketika menggunakan subset yang umum untuk C bersama dengan fitur polimorfik statis .

Bagi mereka yang menemukan aturan ketat C ++ tidak nyaman, kita dapat menggunakan fitur C ++ 11 dengan tipe yang disimpulkan

auto memblock=static_cast<T*>(malloc(n*sizeof(T))); //Mult may overflow...
pengguna877329
sumber
18
Gunakan kompiler C untuk kode C. Gunakan kompiler C ++ untuk kode C ++. Tidak ada, tidak ada tapi Menulis ulang kode C Anda dalam C ++ adalah hal lain, dan mungkin - atau mungkin tidak - sepadan dengan waktu dan risikonya.
Toby Speight
2
Saya ingin menambahkan saran @TobySpeight: Jika Anda perlu menggunakan kode C dalam proyek C ++, Anda biasanya dapat mengkompilasi kode C sebagai C (misalnya gcc -c c_code.c), kode C ++ sebagai C ++ (misalnya g++ -c cpp_code.cpp), dan kemudian menghubungkannya bersama (misalnya gcc c_code.o cpp_code.oatau sebaliknya tergantung pada dependensi proyek). Sekarang seharusnya tidak ada alasan untuk menghilangkan fitur bagus dari kedua bahasa ...
autis
1
@ user877329 Ini adalah alternatif yang lebih masuk akal untuk menambahkan pemain dengan susah payah ke kode yang mengurangi keterbacaan kode, hanya demi menjadi "Kompatibel dengan C ++".
autis
1
Mungkin keuntungan utama dalam konteks ini adalah bahwa C memungkinkan Anda menulis p = malloc(sizeof(*p));, yang tidak perlu diubah sejak awal jika pmengubah nama jenis yang berbeda. "Keuntungan" yang diusulkan dari casting adalah bahwa Anda mendapatkan kesalahan kompilasi jika ptipe yang salah, tetapi bahkan lebih baik jika Just Works.
Peter Cordes
1
Saya ingin menyebutkan bahwa menulis dalam C mungkin diperlukan ketika menargetkan platform yang tidak memiliki kompiler C ++ yang tepat. Pengecualian dan templat adalah fitur yang biasanya membantu c ++ menghasilkan kode yang lebih kecil dan / atau lebih efisien sementara polimorfisme runtime dalam C ++ sebagian besar setara dengan C.
user7860670
15

Tidak, Anda tidak memberikan hasil malloc().

Secara umum, Anda tidak dilemparkan ke atau darivoid * .

Alasan khas yang diberikan untuk tidak melakukan hal itu adalah kegagalan untuk #include <stdlib.h>tidak diperhatikan. Ini bukan masalah lagi untuk waktu yang lama sekarang karena C99 membuat deklarasi fungsi implisit ilegal, jadi jika kompiler Anda sesuai dengan setidaknya C99, Anda akan mendapatkan pesan diagnostik.

Tapi ada alasan yang jauh lebih kuat untuk tidak memperkenalkan cast pointer yang tidak perlu:

Di C, pointer pointer hampir selalu merupakan kesalahan . Ini karena aturan berikut ( §6,5 p7 dalam N1570, konsep terbaru untuk C11):

Objek harus memiliki nilai yang disimpan diakses hanya oleh ekspresi lvalue yang memiliki salah satu dari jenis berikut:
- jenis yang kompatibel dengan jenis objek yang efektif,
- versi yang memenuhi syarat dari jenis yang kompatibel dengan jenis objek yang efektif,
- tipe yang tipe bertanda tangan atau tidak bertanda yang sesuai dengan jenis objek yang efektif,
- jenis tipe yang bertanda tangan atau tidak bertanda yang sesuai dengan versi terkualifikasi dari jenis objek yang efektif,
- tipe agregat atau gabungan yang mencakup satu dari jenis-jenis yang disebutkan di atas di antara para anggotanya (termasuk, secara rekursif, anggota dari sub-agregat atau kesatuan yang terkandung), atau
- jenis karakter.

Ini juga dikenal sebagai aturan aliasing yang ketat . Jadi kode berikut adalah perilaku yang tidak terdefinisi :

long x = 5;
double *p = (double *)&x;
double y = *p;

Dan, terkadang mengejutkan, berikut ini juga:

struct foo { int x; };
struct bar { int x; int y; };
struct bar b = { 1, 2};
struct foo *p = (struct foo *)&b;
int z = p->x;

Terkadang, Anda memang perlu memberikan petunjuk, tetapi mengingat aturan aliasing yang ketat , Anda harus sangat berhati-hati dengannya. Jadi, setiap kejadian penunjuk pointer dalam kode Anda adalah tempat Anda harus memeriksa ulang validitasnya . Oleh karena itu, Anda tidak pernah menulis cast pointer yang tidak perlu.

tl; dr

Singkatnya: Karena dalam C, setiap kejadian pointer penunjuk harus menaikkan bendera merah untuk kode yang membutuhkan perhatian khusus, Anda tidak boleh menulis pointer penunjuk yang tidak perlu .


Catatan samping:

  • Ada beberapa kasus di mana Anda benar - benar membutuhkan gips void *, misalnya jika Anda ingin mencetak pointer:

    int x = 5;
    printf("%p\n", (void *)&x);

    Para pemain diperlukan di sini, karena printf()merupakan fungsi variadik, sehingga konversi implisit tidak berfungsi.

  • Dalam C ++, situasinya berbeda. Tipe-tipe pointer casting agak umum (dan benar) ketika berhadapan dengan objek dari kelas turunan. Oleh karena itu, masuk akal bahwa di C ++, konversi ke dan dari void *yang tidak implisit. C ++ memiliki seluruh rangkaian rasa casting yang berbeda.


sumber
1
Dalam contoh Anda, Anda menghindari void *. ada perbedaan antara cast dari double * ke int * dan sebaliknya. malloc mengembalikan pointel yang disejajarkan dengan tipe standar terbesar sehingga tidak ada aturan aliasing yang dilanggar bahkan jika seseorang melemparkan bentuk pointer yang disejajarkan ini dengan tipe lain.
P__J__
Aliasing sama sekali tidak ada hubungannya dengan penyelarasan dan untuk sisa komentar Anda - Anda jelas tidak mengerti intinya.
@ PeterJ: untuk berjaga-jaga, intinya adalah untuk menghindari lemparan pointer yang tidak perlu, sehingga tidak terlihat seperti sepotong kode yang harus Anda perhatikan.
Masalah aliasing yang ketat tidak benar-benar ada hubungannya dengan void pointer. Untuk mendapatkan bug yang disebabkan oleh pelanggaran alias yang ketat, Anda harus menghapus referensi data yang diarahkan. Dan karena Anda tidak dapat menghapus referensi batal pointer, bug seperti itu per definisi tidak terkait dengan batal pointer tetapi dengan sesuatu yang lain.
Lundin
Sebaliknya, Anda harus membuat aturan untuk melarang semua cast pointer. Tetapi kemudian bagaimana Anda menulis hal-hal seperti rutinitas serialisasi dan pemrograman yang berhubungan dengan perangkat keras? Hal-hal yang merupakan kekuatan C. Gips semacam itu baik-baik saja jika Anda tahu apa yang Anda lakukan.
Lundin
15

Saya lebih suka melakukan pemeran, tetapi tidak secara manual. Favorit saya adalah menggunakan g_newdan g_new0makro dari glib. Jika glib tidak digunakan, saya akan menambahkan makro serupa. Makro tersebut mengurangi duplikasi kode tanpa mengurangi keamanan tipe. Jika Anda salah mengetik, Anda akan mendapatkan pemeran tersirat di antara pointer non-void, yang akan menyebabkan peringatan (kesalahan dalam C ++). Jika Anda lupa menyertakan tajuk yang menentukan g_newdan g_new0, Anda akan mendapatkan kesalahan. g_newdan g_new0keduanya mengambil argumen yang sama, tidak seperti mallocitu membutuhkan lebih sedikit argumen daripada calloc. Tambahkan saja 0untuk mendapatkan memori yang diinisialisasi nol. Kode dapat dikompilasi dengan kompiler C ++ tanpa perubahan.

proski
sumber
12

Casting hanya untuk C ++ bukan C. Jika Anda menggunakan kompiler C ++ Anda lebih baik mengubahnya menjadi kompiler C.


sumber
9

Konsep di balik void pointer adalah bahwa ia dapat dilemparkan ke semua tipe data yang mengapa malloc mengembalikan batal. Anda juga harus mengetahui pengetikan otomatis. Jadi itu tidak wajib untuk melemparkan penunjuk meskipun Anda harus melakukannya. Ini membantu menjaga kode tetap bersih dan membantu debugging

iec2011007
sumber
11
" Itu tidak wajib - meskipun Anda harus melakukannya " - Saya pikir ada kontradiksi di sana!
Toby Speight
5
Saya pikir Anda harus membaca posting ini kepada seseorang, dan lihat apakah mereka mengerti apa yang Anda katakan. Kemudian tulis ulang, buat jelas apa yang ingin Anda katakan. Saya benar-benar tidak mengerti apa jawaban Anda.
Bill Woodger
9

Void pointer adalah pointer umum dan C mendukung konversi implisit dari jenis void pointer ke tipe lain, jadi tidak perlu secara eksplisit mengetiknya.

Namun, jika Anda ingin kode yang sama bekerja dengan sempurna pada platform C ++, yang tidak mendukung konversi implisit, Anda perlu melakukan typecasting, jadi semuanya tergantung pada kegunaan.

dhana govindarajan
sumber
9
  1. Seperti yang dinyatakan lain, itu tidak diperlukan untuk C, tetapi untuk C ++.

  2. Termasuk para pemain memungkinkan program C atau fungsi untuk dikompilasi sebagai C ++.

  3. Dalam C tidak perlu, karena void * secara otomatis dan aman dipromosikan ke jenis pointer lainnya.

  4. Tetapi jika Anda melemparkannya, itu bisa menyembunyikan kesalahan jika Anda lupa menyertakan stdlib.h . Ini dapat menyebabkan crash (atau, lebih buruk lagi, tidak menyebabkan crash sampai nanti di beberapa bagian kode yang sama sekali berbeda).

    Karena stdlib.h berisi prototipe untuk malloc ditemukan. Dengan tidak adanya prototipe untuk malloc, standar mensyaratkan bahwa kompiler C mengasumsikan malloc mengembalikan int. Jika tidak ada pemeran, peringatan dikeluarkan ketika bilangan bulat ini ditugaskan ke pointer; Namun, dengan para pemain, peringatan ini tidak dihasilkan, menyembunyikan bug.

Mohit
sumber
7

Pengecoran malloc tidak perlu dalam C tetapi wajib dalam C ++.

Casting tidak perlu dalam C karena:

  • void * secara otomatis dan aman dipromosikan ke jenis penunjuk lain dalam kasus C.
  • Itu dapat menyembunyikan kesalahan jika Anda lupa untuk memasukkan <stdlib.h>. Ini dapat menyebabkan crash.
  • Jika ukuran pointer dan bilangan bulat berbeda, maka Anda menyembunyikan peringatan dengan melakukan casting dan mungkin kehilangan bit dari alamat yang Anda kembalikan.
  • Jika jenis pointer diubah pada deklarasi, seseorang mungkin juga perlu mengubah semua baris di mana mallocdipanggil dan dilemparkan.

Di sisi lain, casting dapat meningkatkan portabilitas program Anda. yaitu, memungkinkan program C atau fungsi untuk dikompilasi sebagai C ++.

Aashish
sumber
0

Bagi saya, kesimpulan dan kesimpulannya di sini adalah bahwa casting mallocdi C sama sekali TIDAK diperlukan tetapi jika Anda melemparkannya, itu tidak akan mempengaruhi mallockarena mallocmasih akan mengalokasikan untuk Anda ruang memori yang Anda minta. Hal lain yang dapat dibawa pulang adalah alasan atau salah satu alasan orang melakukan casting dan ini adalah untuk memungkinkan mereka mengkompilasi program yang sama baik dalam C atau C ++.

Mungkin ada alasan lain tetapi alasan lain, hampir pasti, akan membuat Anda dalam masalah serius cepat atau lambat.

pasignature
sumber
0

Anda bisa, tetapi tidak perlu menggunakan C. Anda harus melakukan casting jika kode itu dikompilasi sebagai C ++.

ivan.ukr
sumber