Apa perbedaan antara pointer yang menunjuk ke lokasi 0x0 dan pointer yang diatur ke NULL?

12

Apakah pointer yang menunjuk ke 0x0000 sama dengan pointer yang diatur ke NULL? Jika nilai NULL didefinisikan dalam bahasa C, maka lokasi apa yang diterjemahkan secara fisik? Apakah sama dengan 0x0000. Di mana saya dapat menemukan rincian lebih lanjut tentang konsep-konsep ini?

Arpith
sumber
1
Ini sudah ditanyakan pada Stack Overflow - stackoverflow.com/questions/1296843/… . Saya pikir itu batas bagi kita, tetapi saya bersedia untuk memberikan manfaat dari keraguan untuk saat ini.
ChrisF

Jawaban:

12

Poin yang sebagian besar jawaban di sini tidak membahas, setidaknya tidak secara eksplisit, adalah bahwa null pointer adalah nilai yang ada selama eksekusi, dan konstanta null pointer adalah konstruk sintaksis yang ada dalam kode sumber C.

Sebuah nol pointer konstan , sebagai jawaban Karlson ini benar menyatakan, bisa berupa konstan ekspresi bilangan bulat dengan nilai 0 (sederhana 0adalah contoh yang paling umum), atau seperti cor ekspresi void*(seperti (void*)0).

NULLadalah makro, didefinisikan dalam <stddef.h>dan beberapa header standar lainnya, yang meluas ke konstanta penunjuk nol yang ditentukan implementasi . Ekspansi biasanya salah satu 0atau ((void*)0)(tanda kurung luar diperlukan untuk memenuhi aturan bahasa lainnya).

Jadi literal 0, ketika digunakan dalam konteks yang membutuhkan ekspresi tipe pointer, selalu mengevaluasi ke null pointer, yaitu nilai pointer unik yang menunjuk ke objek. Itu tidak menyiratkan apa pun tentang representasi dari pointer nol . Null pointer sangat umum direpresentasikan sebagai semua-bit-nol, tetapi mereka dapat direpresentasikan sebagai apa saja. Tetapi bahkan jika pointer nol direpresentasikan sebagai 0xDEADBEEF, 0atau (void*)0masih merupakan pointer null konstan .

Jawaban ini untuk pertanyaan pada stackoverflow mencakup ini dengan baik.

Ini menyiratkan, antara lain, bahwa memset()atau calloc(), yang dapat mengatur wilayah memori ke semua-bit-nol, tidak akan selalu menetapkan pointer apa pun di wilayah itu menjadi null pointer. Mereka cenderung melakukannya pada sebagian besar implementasi, tetapi bahasa tidak menjaminnya.

Saya tidak tahu mengapa pertanyaan ini tidak dianggap sebagai duplikat dari pertanyaan ini , atau bagaimana topik ini di sini.

Keith Thompson
sumber
1
Salah satu yang membuat saya kesal dengan desain dan evolusi C adalah bahwa digit nol terus digunakan sebagai representasi penunjuk nol yang tidak digunakan lagi. Kembali pada hari-hari awal bahasa (misalnya sebelum munculnya hal-hal seperti prototipe fungsi), pointer dan integer cukup dipertukarkan bahwa menggunakan "0" untuk pointer nol itu sederhana dan itu akan "hanya bekerja". Namun, setelah dibedakan antara kuantitas integer nol dan pointer nol, representasi "0" seharusnya tidak digunakan lagi demi kata kunci atau urutan operator.
supercat
Apakah ini berarti bahwa pointer NULL sebenarnya dapat menunjuk ke beberapa lokasi ketika ditugaskan NULL tergantung pada platform? Konstanta penunjuk nol mungkin merupakan konstruksi sintaksis tetapi apa yang sebenarnya terjadi ketika kode dijalankan? Mari kita anggap konstruk sintaksis ini telah dikompilasi pada platform GNU / Linux. Apa nilai pointer ketika kita menetapkan NULL untuk itu? Apa perbedaan antara alamat ini dan alamat lainnya?
Arpith
1
@ Arpith: Menetapkan NULL, atau sembarang pointer nol , ke objek pointer menetapkan nilai objek ke pointer nol . Pada level mesin, ini mungkin menunjuk ke sejumlah memori yang valid. Mendereferensi pointer nol memiliki perilaku yang tidak jelas; mengakses sepotong memori di alamat 0x0000000adalah perilaku yang valid, seperti yang lainnya secara harfiah. Alamat itu berbeda dari alamat lain dengan (a) membandingkan sama dengan NULL, dan (b) membandingkan tidak setara dengan sembarang pointer ke objek C. Null pointer adalah nilai pointer arbitrer yang digunakan untuk menunjukkan bahwa itu tidak menunjuk ke apa pun.
Keith Thompson
1
Pada level mesin, ini mungkin menunjuk ke sejumlah memori yang valid, tetapi di sebagian besar lingkungan C itu akan menunjuk ke memori yang tidak valid sehingga setiap upaya untuk menggunakan pointer akan menghasilkan jebakan / kesalahan / pengecualian perangkat keras. Biasanya hanya pada platform perangkat keras yang paling sederhana --- yang tanpa dukungan untuk manajemen memori --- di mana penunjuk NULL menunjuk ke lokasi memori yang valid.
Solomon Slow
7

Setiap platform di luar sana bebas menentukan NULL sesuka hati.

Menurut Standar C, jika Anda menetapkan nol ke pointer, itu akan dikonversi ke nilai NULL (untuk platform itu.) Namun, jika Anda mengambil pointer NULL dan melemparkannya ke int, tidak ada jaminan bahwa Anda akan mendapatkan nol di setiap platform di luar sana. Namun kenyataannya adalah bahwa pada kebanyakan platform itu akan menjadi nol.

Informasi tentang itu hal yang dapat Anda temukan di The C Language Specification . Satu sumber, kepercayaan yang tidak bisa saya percayai, adalah ini: http://www.winapi.co.kr/pds/doc/ISO-C-FDIS.1999-04.pdf

Mike Nakis
sumber
2
Jika mereka memilih untuk melepaskan diri dari standar mereka bebas untuk mendefinisikan ulang NULL pointer constant. Sejauh yang saya tahu tidak ada kompiler di luar sana yang melakukan itu.
Karlson
Apakah ada kompiler di luar sana yang tidak mengimplementasikan NULL sebagai 0? Dan apakah NULL dijamin bernilai false?
ugoren
NULL dijamin akan dinilai false oleh standar. Saya tidak tahu apakah ada kompiler (platform, sebenarnya) yang tidak mengimplementasikan NULL sebagai 0, dan saya sangat meragukannya, tetapi standarnya tidak melarangnya, jadi siapa tahu.
Mike Nakis
Ada kebingungan antara representasi abstrak "null pointer constant" (sebagaimana disebutkan dalam spesifikasi) dalam memori, yang mungkin sesuai dengan keinginan pembuat platform dan definisi NULLmakro, yang harus diperluas ke 0dalam C ++ dan salah satu 0atau (void *)0dalam C, karena itu adalah "null pointer constant" yang sebenarnya.
Jan Hudec
Meskipun NULL secara teori dapat didefinisikan sebagai apa saja, namun ada jaminan oleh standar bahwa konstanta int dengan nilai 0 yang diketikkan ke pointer akan menghasilkan null pointer (ISO 9899: 1999 6.3.2.3/3). Makro NULL dari stddef.h harus berupa null pointer (7.17 / 3), jadi akan sangat memberatkan bagi kompiler untuk tidak mengimplementasikan NULL sebagai 0 atau (batal *) 0.
1

Ini didefinisikan dalam bahasa C karena tidak ada satu alamat mesin yang tidak sama yang disamakan. Jika ya, kita tidak perlu abstraksi darinya! Meskipun pada sebagian besar platform, NULL mungkin akhirnya diimplementasikan sebagai 0 dari beberapa jenis atau lainnya, itu salah untuk menganggap bahwa ini berlaku secara universal, jika Anda peduli tentang portabilitas sama sekali.

Kilian Foth
sumber
Itulah standar untuk open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
Karlson
0

Menurut bagian Dokumen Standar C6.3.2.3 :

Ekspresi konstanta bilangan bulat dengan nilai 0, atau ekspresi seperti itu untuk mengetikkan kekosongan *, disebut konstanta penunjuk nol.55) Jika konstanta penunjuk nol dikonversi ke tipe penunjuk, penunjuk yang dihasilkan, disebut penunjuk nol, adalah dijamin untuk membandingkan tidak sama dengan pointer ke objek atau fungsi apa pun.

Sejauh ini saya belum melihat kompiler yang memisahkan diri dari ini.

Karlson
sumber
@ PéterTörök Anda benar itu tyop. :)
Karlson
1
Ya, tetapi perhatikan bahwa itu tidak mengatakan apa-apa tentang pointer yang benar-benar memiliki nilai numerik 0. Mungkin tidak, meskipun pada kebanyakan platform itu.
Jan Hudec