Apa perbedaan antara NULL, '\ 0' dan 0?

309

Di C, tampaknya ada perbedaan antara berbagai nilai nol - NULL, NULdan 0.

Saya tahu bahwa karakter ASCII '0'mengevaluasi ke 48atau 0x30.

The NULLpointer biasanya didefinisikan sebagai:

#define NULL 0

Atau

#define NULL (void *)0

Selain itu, ada NULkarakter '\0'yang tampaknya juga mengevaluasi 0.

Apakah ada kalanya ketiga nilai ini tidak bisa sama?

Apakah ini juga berlaku pada sistem 64 bit?

gnavi
sumber
1
Lihat stackoverflow.com/questions/176989/… untuk beberapa info lebih lanjut mengenai perbedaan antara 0 dan NULL.
David Rodríguez - dribeas
7
Identifier NULtidak ada dalam bahasa atau perpustakaan standar C (atau dalam C ++ sejauh yang saya tahu). Karakter nol kadang-kadang disebut NUL, tetapi C atau C ++ biasanya disebut sebagai '\0'.
Keith Thompson

Jawaban:

351

Catatan: Jawaban ini berlaku untuk bahasa C, bukan C ++.


Null Pointers

Konstanta bilangan bulat konstan 0memiliki arti yang berbeda tergantung pada konteks di mana ia digunakan. Dalam semua kasus, ini masih merupakan konstanta integer dengan nilai 0, itu hanya dijelaskan dengan cara yang berbeda.

Jika sebuah pointer dibandingkan dengan konstanta literal 0, maka ini adalah pemeriksaan untuk melihat apakah pointer tersebut adalah null pointer. Ini 0kemudian disebut sebagai konstanta penunjuk nol. Standar C mendefinisikan yang 0dilemparkan ke tipe void *adalah pointer nol dan konstanta pointer nol.

Selain itu, untuk membantu keterbacaan, makro NULLdisediakan di file header stddef.h. Bergantung pada kompiler Anda, dimungkinkan untuk #undef NULLmendefinisikannya menjadi sesuatu yang aneh.

Oleh karena itu, berikut adalah beberapa cara yang valid untuk memeriksa pointer nol:

if (pointer == NULL)

NULLdidefinisikan untuk membandingkan sama dengan pointer nol. Ini adalah implementasi yang didefinisikan apa definisi sebenarnya NULL, selama itu adalah konstanta penunjuk nol yang valid.

if (pointer == 0)

0 adalah representasi lain dari konstanta penunjuk nol.

if (!pointer)

ifPernyataan ini secara implisit memeriksa "bukan 0", jadi kami membalikkan artinya "adalah 0".

Berikut ini adalah cara-cara INVALID untuk memeriksa pointer nol:

int mynull = 0;
<some code>
if (pointer == mynull)

Untuk kompiler ini bukan pemeriksaan untuk pointer nol, tetapi pemeriksaan kesetaraan pada dua variabel. Ini mungkin bekerja jika mynull tidak pernah mengubah kode dan konstanta optimisasi kompiler melipat 0 ke dalam pernyataan if, tetapi ini tidak dijamin dan kompiler harus menghasilkan setidaknya satu pesan diagnostik (peringatan atau kesalahan) sesuai dengan Standar C.

Perhatikan bahwa apa yang dimaksud dengan pointer nol dalam bahasa C. Tidak masalah pada arsitektur yang mendasarinya. Jika arsitektur yang mendasari memiliki nilai pointer nol yang didefinisikan sebagai alamat 0xDEADBEEF, maka terserah kompiler untuk menyelesaikan masalah ini.

Karena itu, bahkan pada arsitektur lucu ini, cara-cara berikut masih merupakan cara yang valid untuk memeriksa null pointer:

if (!pointer)
if (pointer == NULL)
if (pointer == 0)

Berikut ini adalah cara-cara INVALID untuk memeriksa pointer nol:

#define MYNULL (void *) 0xDEADBEEF
if (pointer == MYNULL)
if (pointer == 0xDEADBEEF)

karena ini dilihat oleh kompiler sebagai perbandingan normal.

Karakter kosong

'\0'didefinisikan sebagai karakter nol - yaitu karakter dengan semua bit diatur ke nol. Ini tidak ada hubungannya dengan pointer. Namun Anda mungkin melihat sesuatu yang mirip dengan kode ini:

if (!*string_pointer)

memeriksa apakah penunjuk string menunjuk pada karakter nol

if (*string_pointer)

memeriksa apakah penunjuk string menunjuk pada karakter yang bukan nol

Jangan bingung dengan pointer nol. Hanya karena representasi bitnya sama, dan ini memungkinkan beberapa kasus cross over yang nyaman, mereka sebenarnya tidak sama.

Selain itu, '\0'adalah (seperti semua literal karakter) konstanta integer, dalam hal ini dengan nilai nol. Jadi '\0'benar-benar setara dengan 0konstanta bilangan bulat tanpa hiasan - satu-satunya perbedaan adalah niat yang disampaikan kepada pembaca manusia ("Saya menggunakan ini sebagai karakter nol.").

Referensi

Lihat Pertanyaan 5.3 dari FAQ comp.lang.c untuk informasi lebih lanjut. Lihat pdf ini untuk standar C. Lihat bagian 6.3.2.3 Petunjuk, paragraf 3.

Andrew Keeton
sumber
3
Terima kasih telah menunjuk ke daftar FAQ. Namun, lihat juga c-faq.com/null/nullor0.html
Sinan Ünür
4
Tidak, Anda tidak akan dibandingkan ptrdengan semua-bit-nol . Ini bukan memcmp, tapi ini perbandingan menggunakan operator builtin. Satu sisi adalah konstanta pointer nol '\0', dan sisi lainnya adalah pointer. Selain dengan dua versi lainnya dengan NULLdan 0. Ketiganya melakukan hal yang sama.
Johannes Schaub - litb
6
Anda mengambil operator perbandingan builtin sebagai hal yang akan membandingkan bit-string. Tapi bukan itu masalahnya. Ini membandingkan dua nilai, yang merupakan konsep abstrak. Jadi null pointer yang secara internal direpresentasikan sebagai 0xDEADBEEFmasih null pointer, tidak peduli apa suka penampilan bitstring, dan masih akan membandingkan sama dengan NULL, 0, \0dan segala bentuk konstan nol pointer lainnya.
Johannes Schaub - litb
2
Anda membuat poin bagus tentang operator pembanding. Saya memoles C99. Dikatakan "Ekspresi konstanta integer dengan nilai 0, atau ekspresi seperti itu untuk mengetikkan void *, disebut konstanta penunjuk nol." Ia juga mengatakan bahwa karakter literal adalah ekspresi konstan bilangan bulat. Jadi, dari properti transitif Anda benar ptr == '\0'.
Andrew Keeton
2
".... mungkin untuk #efef NULL dan mendefinisikan kembali ke sesuatu yang aneh. Siapa pun yang melakukan ini layak untuk ditembak." ini tuanku yang baik membuatku tertawa terbahak-bahak ...
oggiemc
34

Tampaknya sejumlah orang salah paham apa perbedaan antara NULL, '\ 0' dan 0. Jadi, untuk menjelaskan, dan dalam upaya untuk menghindari mengulangi hal-hal yang dikatakan sebelumnya:

Ekspresi konstan dari tipe intdengan nilai 0, atau ekspresi dari tipe ini, dilemparkan ke tipe void *adalah konstanta penunjuk nol , yang jika dikonversi ke sebuah penunjuk menjadi penunjuk nol . Dijamin oleh standar untuk membandingkan tidak sama dengan setiap pointer ke objek atau fungsi apa pun .

NULLadalah makro, didefinisikan sebagai konstanta penunjuk nol .

\0adalah konstruksi yang digunakan untuk mewakili karakter nol , digunakan untuk mengakhiri string.

Sebuah karakter null adalah byte yang memiliki semua set ke 0 bit nya.

amaterasu
sumber
14

Ketiganya mendefinisikan arti nol dalam konteks yang berbeda.

  • konteks pointer - NULL digunakan dan berarti nilai pointer adalah 0, terlepas dari apakah itu 32bit atau 64bit (satu kasus 4 byte yang lainnya 8 byte nol).
  • konteks string - karakter yang mewakili digit nol memiliki nilai hex 0x30, sedangkan karakter NUL memiliki nilai hex 0x00 (digunakan untuk mengakhiri string).

Ketiganya selalu berbeda ketika Anda melihat memori:

NULL - 0x00000000 or 0x00000000'00000000 (32 vs 64 bit)
NUL - 0x00 or 0x0000 (ascii vs 2byte unicode)
'0' - 0x20

Saya harap ini menjelaskannya.

Nasko
sumber
8
Nasko: Evaluasi sizeof('\0')dan kaget.
caf
3
@Nasko: Saya sangat terkejut: dengan gcc, di C: sizeof ('\ 0') == sizeof ('a') == 4, sedangkan dengan g ++, di C ++: sizeof ('\ 0') == sizeof ('a') == 1
David Rodríguez - dribeas
1
@Nasko: Dari standar C (draft, n1124): 'Konstanta karakter integer bertipe int', dengan demikian '\ 0' sebenarnya bertipe int di C, dan dengan demikian sizeof ('\ 0') adalah 4 dalam arsitektur saya (linux, 32bit)
David Rodríguez - dribeas
@ Dribeas - Saya tidak menggambarkannya sebagai konstanta, melainkan apa yang akan Anda lihat sebagai bagian dari string. Saya pasti bisa membuatnya eksplisit. Terima kasih
Nasko
@ DavidRodríguez-dribeas Undid edit "Dikoreksi 'nilai ASCII 0 ke 0x20 (Desember 32)"
chux - Reinstate Monica
6

Jika NULL dan 0 sama dengan konstanta penunjuk nol, yang mana yang harus saya gunakan? di daftar FAQ C mengatasi masalah ini juga:

Pemrogram C harus memahami hal itu NULLdan 0dapat dipertukarkan dalam konteks pointer, dan bahwa uncast 0 sangat dapat diterima. Setiap penggunaan NULL (sebagai lawan dari 0) harus dianggap sebagai pengingat bahwa pointer terlibat; programmer tidak harus bergantung padanya (baik untuk pemahaman mereka sendiri atau kompiler) untuk membedakan pointer 0dari integer0 .

Hanya dalam konteks pointer itu NULLdan 0setara. NULLtidak boleh digunakan ketika jenis lain 0diperlukan, meskipun mungkin berhasil, karena hal itu mengirimkan pesan gaya bahasa yang salah. (Selanjutnya, ANSI memungkinkan definisi NULLmenjadi ((void *)0), yang tidak akan berfungsi sama sekali dalam konteks non-pointer.) Secara khusus, jangan gunakan NULLketika karakter null ASCII ( NUL) diinginkan. Berikan definisi Anda sendiri

#define NUL '\0'

jika kamu harus.

Sinan Ünür
sumber
5

Apa perbedaan antara NULL, '\ 0' dan 0

"karakter nol (NUL)" paling mudah dikesampingkan. '\0'adalah karakter literal. Di C, diimplementasikan sebagai int, jadi, sama dengan 0, yang dari INT_TYPE_SIZE. Dalam C ++, karakter literal diimplementasikan sebagai char, yaitu 1 byte. Ini biasanya berbeda dari NULLatau0 .

Lanjut, NULL adalah nilai penunjuk yang menentukan bahwa suatu variabel tidak menunjuk ke ruang alamat apa pun. Mengesampingkan fakta bahwa biasanya diimplementasikan sebagai nol, itu harus mampu mengekspresikan ruang alamat lengkap arsitektur. Dengan demikian, pada arsitektur 32-bit NULL (kemungkinan) adalah 4-byte dan pada arsitektur 64-bit 8-byte. Ini terserah implementasi C.

Akhirnya, literal 0adalah tipe int, yang berukuran INT_TYPE_SIZE. Nilai default dari INT_TYPE_SIZEdapat berbeda tergantung pada arsitektur.

Apple menulis:

Model data 64-bit yang digunakan oleh Mac OS X dikenal sebagai "LP64". Ini adalah model data umum yang digunakan oleh sistem UNIX 64-bit lainnya dari Sun dan SGI serta Linux 64-bit. Model data LP64 mendefinisikan tipe primitif sebagai berikut:

  • int 32-bit
  • panjang 64-bit
  • long-long juga 64-bit
  • pointer 64-bit

Wikipedia 64-bit :

Kompiler VC ++ Microsoft menggunakan model LLP64.

64-bit data models
Data model short int long  long long pointers Sample operating systems
LLP64      16    32  32    64        64       Microsoft Win64 (X64/IA64)
LP64       16    32  64    64        64       Most Unix and Unix-like systems (Solaris, Linux, etc.)
ILP64      16    64  64    64        64       HAL
SILP64     64    64  64    64        64       ?

Sunting : Menambahkan lebih banyak pada karakter literal.

#include <stdio.h>

int main(void) {
    printf("%d", sizeof('\0'));
    return 0;
}

Kode di atas mengembalikan 4 pada gcc dan 1 pada g ++.

Eugene Yokota
sumber
2
Tidak, '\0'ini bukan nilai 1-byte. Ini adalah karakter literal, yang merupakan ekspresi konstanta bilangan bulat - jadi jika dapat dikatakan memiliki ukuran maka ukurannya adalah int(yang harus setidaknya 2 byte). Jika Anda tidak percaya kepada saya, evaluasi sizeof('\0')dan lihat sendiri. '\0', 0dan 0x0semuanya sepenuhnya sama.
caf
@caf tergantung pada bahasa. Jika Anda tidak percaya kepada saya, cobalah sizeof('\0')menggunakan kompiler C ++.
Eugene Yokota
2
Anda harus menggunakan "% zu" saat mencetak sizeof (sesuatu)
Tidak digunakan
4

Satu-L NUL, itu mengakhiri string.

NULL dua-L menunjuk ke hal yang tidak ada.

Dan aku akan bertaruh banteng emas

Bahwa tidak ada NULLL tiga-L.

Bagaimana Anda menangani NUL?

EvilTeach
sumber
4

Sepotong bagus yang membantu saya ketika memulai dengan C (Diambil dari Pemrograman C Ahli oleh Linden)

The One 'l' nul dan The Two 'l' null

Hafalkan sajak kecil ini untuk mengingat terminologi yang benar untuk pointer dan ASCII nol:

The one "l" NUL ends an ASCII string,

The two "l" NULL points to no thing.

Apologies to Ogden Nash, but the three "l" nulll means check your spelling. 

Karakter ASCII dengan pola bit nol disebut "NUL". Nilai penunjuk khusus yang berarti titik penunjuk di mana-mana adalah "NULL". Kedua istilah itu tidak saling berarti.

dlmeetei
sumber
Jauh lebih sederhana: NULadalah kode kontrol seperti BEL, VT, HT, SOTdll dan dengan demikian memiliki max. 3 karakter.
glglgl
2

"NUL" bukan 0, tetapi mengacu pada karakter ASCII NUL. Setidaknya, begitulah cara saya melihatnya digunakan. Pointer nol sering didefinisikan sebagai 0, tetapi ini tergantung pada lingkungan tempat Anda menjalankannya, dan spesifikasi sistem operasi atau bahasa apa pun yang Anda gunakan.

Dalam ANSI C, penunjuk nol ditentukan sebagai nilai integer 0. Jadi dunia mana pun yang tidak benar tidak sesuai dengan ANSI C.

peterb
sumber
1

Byte dengan nilai 0x00adalah, pada tabel ASCII, karakter khusus disebut NULatau NULL. Dalam C, karena Anda tidak boleh menanamkan karakter kontrol dalam kode sumber Anda, ini diwakili dalam string C dengan 0 yang diloloskan, yaitu \0,.

Tapi NULL sejati bukan nilai. Itu adalah tidak adanya nilai. Untuk sebuah pointer, itu berarti pointer itu tidak ada hubungannya. Dalam database, itu berarti tidak ada nilai dalam bidang (yang tidak sama dengan mengatakan bidang kosong, 0, atau diisi dengan spasi).

Nilai aktual yang digunakan format sistem atau file basis data tertentu untuk mewakili NULLbelum tentu 0x00.

richardtallent
sumber
0

NULLtidak dijamin menjadi 0 - nilai pastinya tergantung arsitektur. Sebagian besar arsitektur besar mendefinisikannya(void*)0 .

'\0' akan selalu sama dengan 0, karena itulah cara byte 0 dikodekan dalam karakter literal.

Saya tidak ingat apakah kompiler C diharuskan menggunakan ASCII - jika tidak, '0'mungkin tidak selalu sama dengan 48. Terlepas dari itu, kemungkinan besar Anda tidak akan pernah menemukan sistem yang menggunakan set karakter alternatif seperti EBCDIC kecuali jika Anda bekerja dengan sangat sistem tidak jelas.

Ukuran dari berbagai jenis akan berbeda pada sistem 64-bit, tetapi nilai integer akan sama.


Beberapa komentator telah menyatakan keraguan bahwa NULL sama dengan 0, tetapi tidak menjadi nol. Berikut adalah contoh program, bersama dengan output yang diharapkan pada sistem seperti itu:

#include <stdio.h>

int main () {
    size_t ii;
    int *ptr = NULL;
    unsigned long *null_value = (unsigned long *)&ptr;
    if (NULL == 0) {
        printf ("NULL == 0\n"); }
    printf ("NULL = 0x");
    for (ii = 0; ii < sizeof (ptr); ii++) {
        printf ("%02X", null_value[ii]); }
    printf ("\n");
    return 0;
}

Program itu dapat mencetak:

NULL == 0
NULL = 0x00000001
John Millikin
sumber
2
OP bertanya tentang '\ 0' (karakter NUL), bukan '0' (karakter nol)
Chris Lutz
2
@ Chris: '\ 0' bukan NULL, itu byte 0 yang dikodekan dalam oktal dalam karakter literal.
John Millikin
2
Dalam C ++, standar menjamin bahwa konversi dari nilai integer 0 ke sebuah pointer akan selalu menghasilkan pointer nol. Dalam C ++, 0 dijamin menjadi null pointer, sementara di sisi lain NULL adalah makro dan pembuat kode jahat dapat mendefinisikannya kembali sebagai sesuatu yang berbeda.
David Rodríguez - dribeas
6
Dan NULL dijamin menjadi 0. Pola bit dari sebuah pointer NULL tidak dijamin menjadi semua nol, tetapi konstanta NULL adalah, dan akan selalu menjadi, 0.
jalf
2
Kalimat pertama Anda salah - NULL tidak dapat didefinisikan sebagai (void *) 0 di C ++ karena tidak ada konversi implisit dari void * ke pointer lain (tidak seperti di C).
-2

(void *) 0 adalah NULL, dan '\ 0' mewakili akhir dari string.

Shinxg
sumber