Mengapa membatalkan dalam C berarti tidak membatalkan?

25

Dalam bahasa yang sangat diketik seperti Java dan C #, void(atau Void) sebagai tipe kembali untuk metode tampaknya berarti:

Metode ini tidak mengembalikan apa pun. Tidak ada. Tidak kembali Anda tidak akan menerima apa pun dari metode ini.

Apa yang benar-benar aneh adalah bahwa dalam C, void sebagai tipe pengembalian atau bahkan sebagai tipe parameter metode berarti:

Bisa jadi apa saja. Anda harus membaca kode sumber untuk mengetahuinya. Semoga berhasil. Jika itu sebuah pointer, Anda harus benar-benar tahu apa yang Anda lakukan.

Perhatikan contoh-contoh berikut dalam C:

void describe(void *thing)
{
    Object *obj = thing;
    printf("%s.\n", obj->description);
}

void *move(void *location, Direction direction)
{
    void *next = NULL;

    // logic!

    return next;
}

Jelas, metode kedua mengembalikan pointer, yang menurut definisi bisa apa saja.

Karena C lebih tua dari Java dan C #, mengapa bahasa-bahasa ini mengadopsi yang voidberarti "tidak ada" sementara C menggunakannya sebagai "tidak ada atau apa pun (ketika pointer)"?

Naftuli Kay
sumber
138
Judul pertanyaan dan teks Anda dibicarakan voidsementara contoh kode menggunakan void*sesuatu yang sama sekali berbeda.
4
Perhatikan juga bahwa Java dan C # memiliki konsep yang sama, mereka hanya menyebutnya Objectdalam satu kasus untuk disatukan.
Mooing Duck
4
@ Mephy mereka tidak diketik dengan benar? Dengan C # menggunakan mengetik bebek, maksud Anda dynamicjenis yang jarang digunakan?
Axarydax
9
@Mephy: Terakhir kali saya memeriksa Wikipedia terdaftar sebelas arti yang saling bertentangan untuk "sangat diketik". Mengatakan bahwa "C # tidak diketik" tidak berarti
Eric Lippert
8
@LightnessRacesinOrbit: Tidak, intinya adalah bahwa tidak ada definisi otoritatif dari istilah tersebut. Wikipedia bukanlah preskriptif sumber daya yang memberitahu Anda apa yang benar arti dari istilah ini. Ini adalah sumber deskriptif . Fakta bahwa kata itu menggambarkan sebelas makna kontradiktif yang berbeda adalah bukti bahwa istilah itu tidak dapat digunakan dalam percakapan tanpa dengan hati-hati mendefinisikannya . Melakukan sebaliknya berarti bahwa peluang sangat baik, orang-orang dalam percakapan akan membicarakan masa lalu, bukan untuk, satu sama lain.
Eric Lippert

Jawaban:

58

Kata kunci void (bukan penunjuk) berarti "tidak ada" dalam bahasa tersebut. Ini konsisten.

Seperti yang Anda catat, void*berarti "penunjuk ke apa saja" dalam bahasa yang mendukung pointer mentah (C dan C ++). Ini adalah keputusan yang disayangkan karena seperti yang Anda sebutkan, itu membuatvoid dua hal berbeda.

Saya belum dapat menemukan alasan historis di balik penggunaan kembali yang voidberarti "tidak ada" dan "apa pun" dalam konteks yang berbeda, namun C melakukan ini di beberapa tempat lain. Sebagai contoh,static memiliki tujuan yang berbeda dalam konteks yang berbeda. Jelas ada preseden dalam bahasa C untuk menggunakan kembali kata kunci dengan cara ini, terlepas dari apa yang dipikirkan orang tentang praktik tersebut.

Java dan C # cukup berbeda untuk membuat jeda bersih untuk memperbaiki beberapa masalah ini. Java dan "aman" C # juga tidak mengizinkan pointer baku dan tidak perlu kompatibilitas C mudah (tidak aman C # tidak memungkinkan pointer tetapi sebagian besar C # kode tidak termasuk dalam kategori ini). Ini memungkinkan mereka untuk mengubah segalanya sedikit tanpa khawatir tentang kompatibilitas mundur. Salah satu cara untuk melakukan ini adalah memperkenalkan kelas Objectpada akar hierarki dari mana semua kelas mewarisi, sehingga Objectreferensi melayani fungsi yang sama void*tanpa nastiness masalah jenis dan manajemen memori mentah.


sumber
2
Saya akan memberikan referensi ketika saya sampai di rumah
4
They also do not allow raw pointers and do not need easy C compatibility.Salah. C # memiliki pointer. Mereka biasanya (dan biasanya harus), tetapi mereka ada di sana.
Magus
8
Mengenai alasan mereka digunakan kembali void: alasan yang jelas adalah untuk menghindari memasukkan kata kunci baru (dan berpotensi merusak program yang ada). Seandainya mereka memperkenalkan kata kunci khusus (mis. unknown), Maka void*akan menjadi konstruksi yang tidak bermakna (dan mungkin ilegal), dan unknownakan sah hanya dalam bentuk unknown*.
jamesdlin
20
Bahkan dalam void *, voidberarti "tidak ada", bukan "apa pun". Anda tidak dapat melakukan dereferensi a void *, Anda harus terlebih dahulu melemparkannya ke jenis pointer lain.
oefe
2
@efe Saya pikir tidak ada artinya untuk membelah rambut itu, karena voiddan void*tipe yang berbeda (sebenarnya, void"tidak ada tipe"). Masuk akal juga mengatakan " intin int*berarti sesuatu". Tidak, begitu Anda mendeklarasikan variabel pointer, Anda mengatakan "ini adalah alamat memori yang mampu menyimpan sesuatu." Dalam kasus void*, Anda mengatakan "alamat ini menyimpan sesuatu tetapi sesuatu tidak dapat disimpulkan dari jenis pointer."
32

voiddan void*ada dua hal yang berbeda. voiddi C berarti hal yang persis sama dengan di Jawa, tidak adanya nilai kembali. A void*adalah pointer dengan tidak adanya tipe.

Semua petunjuk dalam C harus dapat direferensikan. Jika Anda melakukan dereferensi void*, tipe apa yang akan Anda dapatkan? Ingat pointer C tidak membawa informasi tipe runtime, jadi tipenya harus diketahui pada waktu kompilasi.

Mengingat konteks itu, satu-satunya hal yang dapat Anda lakukan secara logis dengan dereferensi void*adalah mengabaikannya, yang persis perilaku yang ditunjukkan oleh voidtipe tersebut.

Karl Bielefeldt
sumber
1
Saya setuju sampai Anda mendapatkan bit "abaikan". Mungkin saja benda yang dikembalikan berisi informasi tentang bagaimana menafsirkannya. Dengan kata lain, itu bisa menjadi setara C dari varian BASIC. "Ketika Anda mendapatkan ini, lihat untuk mencari tahu apa itu - saya tidak bisa memberi tahu Anda di muka apa yang akan Anda temukan".
Floris
1
Atau dengan kata lain, secara hipotetis saya bisa meletakkan "deskriptor tipe" yang ditentukan pemrogram dalam byte pertama di lokasi memori yang dituju oleh pointer, yang akan memberi tahu saya tipe data apa yang dapat saya temukan dalam byte berikutnya.
Robert Harvey
1
Tentu saja, tetapi dalam C diputuskan untuk menyerahkan detail-detail itu kepada programmer, daripada memanggangnya ke dalam bahasa. Dari sudut pandang bahasa , tidak tahu harus berbuat apa selain mengabaikan. Ini menghindari overhead yang selalu menyertakan informasi jenis sebagai byte pertama ketika dalam kebanyakan kasus penggunaan Anda dapat menentukannya secara statis.
Karl Bielefeldt
4
@ RobertTarvey ya, tapi kemudian Anda tidak melakukan dereferencing pointer kosong; Anda melempar pointer kosong ke pointer char dan kemudian mereferensikan pointer char.
user253751
4
@ Floris gcctidak setuju dengan Anda. Jika Anda mencoba menggunakan nilai, buat gccpesan kesalahan yang mengatakan error: void value not ignored as it ought to be.
kasperd
19

Mungkin akan lebih berguna untuk dianggap voidsebagai tipe pengembalian. Kemudian metode kedua Anda akan membaca "metode yang mengembalikan pointer yang tidak diketik."

Robert Harvey
sumber
Itu membantu. Sebagai seseorang yang (akhirnya!) Belajar C setelah bertahun-tahun menghabiskan waktu dalam bahasa berorientasi objek, petunjuk adalah sesuatu yang merupakan konsep yang sangat baru bagi saya. Tampaknya ketika mengembalikan pointer, voidkira-kira setara dengan *bahasa seperti ActionScript 3 yang hanya berarti "semua tipe pengembalian."
Naftuli Kay
5
Ya, voiditu bukan wildcard. Pointer hanyalah alamat memori. Menempatkan suatu tipe sebelum tulisan *"di sini adalah tipe data yang dapat Anda temukan di alamat memori yang dirujuk oleh pointer ini." Meletakkan voidsebelum *kata ke kompiler "Saya tidak tahu jenisnya; kembalikan saja pointer mentahnya, dan saya akan mencari tahu apa yang harus dilakukan dengan data yang ditunjukkannya."
Robert Harvey
2
Saya bahkan akan mengatakan bahwa void*poin pada "kekosongan". Sebuah pointer kosong tanpa menunjuk apa pun. Tetap Anda bisa melemparkannya seperti pointer lainnya.
Robert
11

Mari kita kencangkan terminologinya sedikit.

Dari standar C 2011 online :

6.2.5 Jenis
...
19 voidJenis ini terdiri dari serangkaian nilai kosong; itu adalah tipe objek tidak lengkap yang tidak dapat diselesaikan.
...
6.3 Conversions
...
6.3.2.2 void

1 Nilai (tidak ada) dari voidekspresi (ekspresi yang memiliki tipe void) tidak boleh digunakan dengan cara apa pun, dan konversi implisit atau eksplisit (kecuali untuk void) tidak boleh diterapkan untuk ungkapan seperti itu. Jika ekspresi jenis apa pun dievaluasi sebagai void ekspresi, nilainya atau penunjuknya dibuang. ( voidEkspresi dievaluasi untuk efek sampingnya.)

6.3.2.3 Petunjuk

1 Sebuah pointer kevoiddapat dikonversi ke atau dari pointer ke tipe objek apa pun. Pointer ke semua jenis objek dapat dikonversi ke pointer untuk membatalkan dan kembali lagi; hasilnya harus sama dengan pointer asli.

Sebuah voidekspresi tidak memiliki nilai (meskipun mungkin memiliki efek samping). Jika saya memiliki fungsi yang didefinisikan untuk kembali void, seperti:

void foo( void ) { ... }

lalu telepon

foo();

tidak mengevaluasi ke suatu nilai; Saya tidak dapat menetapkan hasil untuk apa pun, karena tidak ada hasil.

Sebuah pointer ke voiddasarnya adalah "generik" jenis pointer; Anda dapat menetapkan nilai void *untuk setiap jenis penunjuk objek lain tanpa perlu pemeran eksplisit (itulah sebabnya semua programmer C akan berteriak kepada Anda untuk memberikan hasil malloc).

Anda tidak dapat secara langsung dereferensi a void *; Anda harus terlebih dahulu menetapkannya ke jenis penunjuk objek yang berbeda sebelum Anda dapat mengakses objek runcing-ke.

voidpointer digunakan untuk mengimplementasikan antarmuka generik (kurang lebih); contoh kanonik adalah qsortfungsi pustaka, yang dapat mengurutkan array jenis apa pun, asalkan Anda menyediakan fungsi perbandingan yang sadar jenis.

Ya, menggunakan kata kunci yang sama untuk dua konsep yang berbeda (tidak ada nilai vs penunjuk umum) membingungkan, tetapi tidak seperti tidak ada preseden; staticmemiliki banyak arti berbeda baik dalam C dan C ++.

John Bode
sumber
9

Dalam Java dan C #, batal sebagai tipe pengembalian untuk metode tampaknya berarti: metode ini tidak mengembalikan apa pun. Tidak ada. Tidak kembali Anda tidak akan menerima apa pun dari metode ini.

Pernyataan itu benar. Itu benar untuk C dan C ++ juga.

di C, batal sebagai tipe kembali atau bahkan sebagai tipe metode metode berarti sesuatu yang berbeda.

Pernyataan itu salah. voidsebagai tipe pengembalian di C atau C ++ berarti hal yang sama yang dilakukannya di C # dan Java. Anda bingung voiddengan void*. Mereka sangat berbeda.

Bukankah ini membingungkan voiddan void*berarti dua hal yang sama sekali berbeda?

Ya.

Apa itu pointer? Apa itu void pointer?

Sebuah pointer adalah nilai yang dapat dereferenced . Dereferencing pointer yang valid memberikan lokasi penyimpanan tipe menunjuk-ke . Sebuah pointer kekosongan adalah pointer yang tidak memiliki tertentu menunjuk-mengetik; itu harus dikonversi ke jenis pointer yang lebih spesifik sebelum nilainya didereferensi untuk menghasilkan lokasi penyimpanan .

Apakah void pointer sama dalam C, C ++, Java dan C #?

Java tidak memiliki void pointer; C # tidak. Mereka sama seperti di C dan C ++ - nilai pointer yang tidak memiliki tipe spesifik yang terkait dengannya, yang harus dikonversi ke tipe yang lebih spesifik sebelum mendereferensi untuk menghasilkan lokasi penyimpanan.

Karena C lebih tua dari Java dan C #, mengapa bahasa-bahasa ini mengadopsi void sebagai yang berarti "tidak ada" sementara C menggunakannya sebagai "tidak ada atau apa pun (ketika pointer)"?

Pertanyaannya tidak jelas karena mengandaikan kepalsuan. Mari kita tanyakan beberapa pertanyaan yang lebih baik.

Mengapa Java dan C # mengadopsi konvensi yang voidmerupakan tipe pengembalian yang valid, alih-alih, misalnya, menggunakan konvensi Visual Basic yang fungsinya tidak pernah batal kembali dan subrutin selalu batal kembali?

Untuk terbiasa dengan programmer yang datang ke Jawa atau C # dari bahasa di mana voidadalah tipe pengembalian.

Mengapa C # mengadopsi konvensi membingungkan yang void*memiliki arti yang sama sekali berbeda dari void?

Untuk terbiasa dengan programmer yang datang ke C # dari bahasa di mana void*adalah jenis pointer.

Eric Lippert
sumber
5
void describe(void *thing);
void *move(void *location, Direction direction);

Fungsi pertama tidak mengembalikan apa pun. Fungsi kedua mengembalikan pointer kosong. Saya akan menyatakan bahwa fungsi kedua sebagai

void* move(void* location, Direction direction);

Jika mungkin membantu jika Anda menganggap "void" sebagai makna "tanpa makna". Nilai kembalinya describeadalah "tanpa makna". Mengembalikan nilai dari fungsi seperti itu ilegal karena Anda memberi tahu kompiler bahwa nilai kembali tidak berarti. Anda tidak dapat menangkap nilai kembali dari fungsi itu karena itu tanpa makna. Anda tidak dapat mendeklarasikan variabel tipe voidkarena itu tanpa makna. Sebagai contoh void nonsense;adalah omong kosong dan sebenarnya ilegal. Perhatikan juga bahwa array batalvoid void_array[42]; juga tidak masuk akal.

Pointer untuk membatalkan ( void*) adalah sesuatu yang berbeda. Ini adalah pointer, bukan array. Baca void*artinya penunjuk yang menunjuk ke sesuatu "tanpa makna". Pointer adalah "tanpa makna", yang berarti tidak masuk akal untuk merujuk pointer seperti itu. Mencoba melakukannya sebenarnya ilegal. Kode yang dereferensi pointer kosong tidak akan dikompilasi.

Jadi, jika Anda tidak bisa melakukan dereferensi pointer kosong, dan Anda tidak bisa membuat array void, bagaimana Anda bisa menggunakannya? Jawabannya adalah pointer ke tipe apa pun dapat dilemparkan ke dan dari void*. Casting beberapa pointer ke void*dan casting kembali ke pointer ke tipe asli akan menghasilkan nilai yang sama dengan pointer asli. Standar C menjamin perilaku ini. Alasan utama Anda melihat begitu banyak pointer kosong di C adalah bahwa kemampuan ini menyediakan cara untuk mengimplementasikan penyembunyian informasi dan pemrograman berbasis objek dalam bahasa yang sangat berorientasi objek.

Akhirnya, alasan yang sering Anda lihat movedinyatakan sebagai void *move(...)bukan void* move(...)karena meletakkan tanda bintang di sebelah nama daripada tipe adalah praktik yang sangat umum di C. Alasannya adalah bahwa deklarasi berikut akan membuat Anda dalam masalah besar: int* iptr, jptr;Ini akan membuat Anda pikir Anda mendeklarasikan dua pointer ke sebuah int. Kamu bukan. Deklarasi ini membuat jptrsebuah intdaripada pointer ke int. Deklarasi yang tepat adalah int *iptr, *jptr;Anda dapat berpura-pura tanda bintang milik jenis jika Anda tetap berpegang pada praktik hanya mendeklarasikan satu variabel per pernyataan deklarasi. Namun perlu diingat bahwa Anda berpura-pura.

David Hammen
sumber
"Kode yang dereferensi pointer nol tidak akan dikompilasi." Saya pikir Anda kode berarti bahwa dereferences sebuah kekosongan pointer tidak dapat dikompilasi. Compiler tidak melindungi Anda dari penereferensi pointer nol; itu adalah masalah runtime.
Cody Grey
@CodyGray - Terima kasih! Memperbaiki itu. Kode yang mereferensi pointer nol akan dikompilasi (selama pointer tidak void* null_ptr = 0;).
David Hammen
2

Sederhananya, tidak ada perbedaan . Biarkan saya memberi Anda beberapa contoh.

Katakanlah saya memiliki kelas yang disebut Mobil.

Car obj = anotherCar; // obj is now of type Car
Car* obj = new Car(); // obj is now a pointer of type Car
void obj = 0; // obj has no type
void* = new Car(); // obj is a pointer with no type

Saya percaya di sini kebingungan di sini didasarkan dari bagaimana Anda mendefinisikan voidvs void*. Tipe pengembalian voidberarti "Saya tidak mengembalikan apa-apa", sedangkan jenis kembali void*berarti "Saya mengembalikan pointer jenis apa-apa".

Ini disebabkan oleh fakta bahwa pointer adalah case khusus. Objek pointer akan selalu menunjuk ke lokasi di memori, apakah ada objek yang valid di sana atau tidak. Apakah void* carreferensi saya byte, kata, Mobil, atau sepeda tidak masalah karena void*poin saya untuk sesuatu tanpa jenis yang ditentukan. Terserah kita untuk menentukannya nanti.

Dalam bahasa seperti C # dan Java, memori dikelola dan konsep pointer dimasukkan ke kelas Object. Alih-alih memiliki referensi ke objek bertipe "tidak ada", kita tahu bahwa setidaknya objek kita bertipe "Objek". Biarkan saya jelaskan alasannya.

Dalam C / C ++ konvensional jika Anda membuat objek dan menghapus pointer-nya, maka tidak mungkin untuk mendapatkan akses ke objek itu. Inilah yang dikenal sebagai kebocoran memori .

Di C # / Java, semuanya adalah objek dan ini memungkinkan runtime untuk melacak setiap objek. Tidak perlu tahu bahwa objek saya adalah Mobil, hanya perlu mengetahui beberapa informasi dasar yang sudah dijaga oleh kelas Object.

Bagi kita programmer, itu berarti bahwa banyak informasi yang harus kita tangani secara manual di C / C ++ diurus untuk kita oleh kelas Object, menghilangkan kebutuhan untuk case khusus yaitu pointer.

Ikan kecil
sumber
"kekosongan saya * menunjuk ke sesuatu tanpa tipe yang didefinisikan" - tidak persis. Lebih tepat untuk mengatakan bahwa ini adalah pointer ke nilai panjang nol (hampir seperti sebuah array dengan 0 elemen, tetapi bahkan tanpa tipe informasi yang terkait dengan array).
Scott Whitlock
2

Saya akan mencoba mengatakan bagaimana seseorang dapat memikirkan hal-hal ini dalam C. Bahasa resmi dalam standar C tidak benar-benar nyaman void, dan saya tidak akan mencoba untuk sepenuhnya konsisten dengannya.

Tipe void ini bukan warga negara kelas satu di antara tipe-tipe tersebut. Meskipun ini adalah tipe objek, itu tidak bisa menjadi tipe objek apa pun (atau nilai), bidang, atau parameter fungsi; namun itu bisa menjadi tipe kembalinya suatu fungsi, dan dengan demikian menjadi tipe ekspresi (pada dasarnya dari panggilan fungsi tersebut, tetapi ekspresi yang dibentuk dengan operator bersyarat juga dapat memiliki tipe batal). Tetapi bahkan penggunaan minimal voidsebagai tipe nilai yang di atas membiarkan pintu terbuka, yaitu mengakhiri fungsi yang kembali voiddengan pernyataan bentuk di return E;mana Eekspresi tipe void, secara eksplisit dilarang dalam C (diizinkan dalam C ++, tetapi karena alasan tidak berlaku untuk C).

Jika objek bertipe void diizinkan, mereka akan memiliki 0 bit (yaitu jumlah informasi dalam nilai ekspresi voidtipe); itu tidak akan menjadi masalah besar yang memungkinkan objek seperti itu, tetapi mereka akan menjadi agak tidak berguna (objek berukuran 0 akan memberikan beberapa kesulitan dengan mendefinisikan aritmatika pointer, yang mungkin sebaiknya hanya dilarang). Himpunan nilai yang berbeda dari objek seperti itu akan memiliki satu (sepele) elemen; nilainya dapat diambil, sepele karena tidak memiliki substansi apa pun, tetapi tidak dapat dimodifikasi (tidak memiliki nilai yang berbeda ). Oleh karena itu standar ini bingung dalam mengatakan voidterdiri dari seperangkat nilai kosong; tipe seperti itu bisa berguna untuk menggambarkan ekspresi itu tidak bisadievaluasi (seperti lompatan atau panggilan non-terminasi) meskipun bahasa C sebenarnya tidak menggunakan tipe seperti itu.

voidDilarang sebagai tipe nilai, telah digunakan dalam setidaknya dua cara yang tidak berhubungan langsung untuk menunjuk "terlarang": menetapkan (void)sebagai spesifikasi parameter dalam tipe fungsi berarti memberikan argumen kepada mereka dilarang (sementara '()' sebaliknya akan berarti semuanya diperbolehkan, dan ya, bahkan memberikan voidekspresi sebagai argumen untuk fungsi dengan (void)spesifikasi parameter dilarang), dan menyatakan void *pberarti bahwa ekspresi dereferencing *pdilarang (tetapi bukan bahwa itu adalah ekspresi tipe yang valid void). Jadi Anda benar bahwa penggunaan voidini tidak benar-benar konsistenvoid jenis ekspresi yang valid. Namun objek bertipevoid*sebenarnya bukan penunjuk ke nilai jenis apa pun, itu berarti nilai yang diperlakukan sebagai penunjuk meskipun tidak dapat ditereferensi dan penunjuk aritmatika dengannya dilarang. "Diperlakukan sebagai pointer" kemudian benar-benar hanya berarti dapat dilemparkan dari dan ke semua jenis pointer tanpa kehilangan informasi. Namun itu juga dapat digunakan untuk melemparkan nilai integer ke dan dari, sehingga tidak harus mengarah ke apa pun.

Marc van Leeuwen
sumber
Sebenarnya, itu dapat dilemparkan dari dan ke semua jenis penunjuk objek tanpa kehilangan informasi tetapi tidak selalu dari dan ke . Secara umum pemain dari void*jenis pointer lain mungkin kehilangan informasi (atau bahkan memiliki UB, saya tidak dapat mengingatnya), tetapi jika nilai void*berasal dari casting sebuah pointer dari jenis yang sama dengan yang sekarang Anda casting, maka tidak.
Steve Jessop
0

Dalam C # dan Java, setiap kelas diturunkan dari suatu Objectkelas. Karenanya kapan pun kita ingin memberikan referensi ke "sesuatu", kita dapat menggunakan referensi tipe Object.

Karena kita tidak perlu menggunakan void pointer untuk tujuan itu dalam bahasa-bahasa ini, voidtidak harus berarti "sesuatu atau tidak sama sekali" di sini.

Sunting Reg
sumber
0

Dalam C, dimungkinkan untuk memiliki pointer ke hal-hal dari tipe apa pun [pointer berperilaku sebagai tipe referensi]. Pointer dapat mengidentifikasi objek dari tipe yang dikenal, atau dapat mengidentifikasi objek dengan tipe yang arbitrer (tidak diketahui). Pembuat C memilih untuk menggunakan sintaksis umum yang sama untuk "penunjuk ke jenis sembarang jenis" seperti untuk "penunjuk ke jenis jenis tertentu". Karena sintaks dalam kasus terakhir memerlukan token untuk menentukan apa jenisnya, sintaks sebelumnya mengharuskan meletakkan sesuatu di mana token itu akan berada jika jenis itu diketahui. C memilih untuk menggunakan kata kunci "void" untuk tujuan itu.

Dalam Pascal, seperti halnya dengan C, dimungkinkan untuk memiliki petunjuk tentang hal-hal apa pun; dialek yang lebih populer dari Pascal juga memungkinkan "penunjuk ke jenis yang sewenang-wenang", tetapi alih-alih menggunakan sintaks yang sama seperti yang mereka gunakan untuk "penunjuk ke jenis jenis tertentu", mereka hanya menyebut yang pertama sebagai Pointer.

Di Jawa, tidak ada tipe variabel yang ditentukan pengguna; semuanya adalah referensi objek primitif atau heap. Seseorang dapat mendefinisikan hal-hal dari tipe "referensi ke objek tumpukan tipe tertentu" atau "referensi ke objek tumpukan tipe sewenang-wenang". Yang pertama hanya menggunakan nama jenis tanpa tanda baca khusus untuk menunjukkan bahwa itu adalah referensi (karena tidak bisa apa pun); yang terakhir menggunakan nama tipe Object.

Penggunaan void*sebagai nomenklatur untuk pointer ke sesuatu yang jenis sewenang-wenang sejauh yang saya tahu unik untuk C dan turunan langsung seperti C ++; bahasa lain yang saya tahu menangani konsep dengan hanya menggunakan jenis yang diberi nama berbeda.

supercat
sumber
-1

Anda dapat memikirkan kata kunci voidseperti kosong struct( Dalam C99, struct kosong tampaknya tidak diizinkan , dalam .NET dan C ++ kata kunci tersebut mengambil lebih dari 0 memori, dan terakhir saya ingat semua yang ada di Jawa adalah kelas):

struct void {
};

... yang artinya adalah tipe dengan panjang 0. Ini adalah cara kerjanya ketika Anda melakukan panggilan fungsi yang mengembalikan void... alih-alih mengalokasikan 4 byte atau lebih di stack untuk nilai pengembalian integer, itu tidak mengubah penumpukan stack sama sekali (menambahnya dengan panjang 0) ).

Jadi, jika Anda mendeklarasikan beberapa variabel seperti:

int a;
void b;
int c;

... dan kemudian Anda mengambil alamat variabel-variabel itu, maka mungkin bdan cmungkin terletak di tempat yang sama dalam memori, karena bmemiliki panjang nol. Jadi a void*adalah pointer di memori ke tipe built-in dengan panjang nol. Fakta bahwa Anda mungkin tahu bahwa ada sesuatu segera setelah itu yang mungkin berguna bagi Anda adalah masalah lain, dan mengharuskan Anda untuk benar-benar tahu apa yang Anda lakukan (dan berbahaya).

Scott Whitlock
sumber
Satu-satunya kompiler yang saya tahu yang menetapkan panjang untuk mengetikkan kekosongan adalah gcc, dan gcc menetapkan panjangnya 1.
Joshua