NULL, '\ 0' ve 0 arasındaki fark nedir?


309

C'de, sıfır - NULL, NULve arasındaki çeşitli değerler arasında farklar vardır 0.

ASCII karakterinin veya olarak '0'değerlendirildiğini biliyorum .480x30

NULLİşaretçi genellikle şu şekilde tanımlanır:

#define NULL 0

Veya

#define NULL (void *)0

Buna ek olarak, değerlendirilmesi gereken bir NULkarakter de var.'\0'0

Bu üç değerin eşit olamayacağı zamanlar var mı?

Bu 64 bit sistemlerde de geçerli mi?


1
Bkz stackoverflow.com/questions/176989/... 0 ve NULL arasındaki farklar içine biraz daha fazla bilgi için.
David Rodríguez - dribeas

7
Tanımlayıcı NULC standart dilinde veya kütüphanesinde (veya bildiğim kadarıyla C ++) mevcut değil. Boş karakter bazen NUL olarak adlandırılır, ancak C veya C ++ genellikle sadece olarak adlandırılır '\0'.
Keith Thompson

Yanıtlar:


351

Not: Bu cevap C ++ için değil C dili için geçerlidir.


Boş İşaretçiler

Tamsayı sabit değişmezi 0, kullanıldığı bağlama bağlı olarak farklı anlamlara sahiptir. Her durumda, hala değeri olan bir tamsayı sabitidir0 , sadece farklı şekillerde açıklanır.

Bir işaretçi sabit değişmez değerle karşılaştırılıyorsa 0, bu işaretçinin boş bir işaretçi olup olmadığını kontrol eder. Bu 0daha sonra bir boş işaretçi sabiti olarak adlandırılır. C standardı, bu 0türevoid * hem boş gösterici hem de boş gösterici sabiti .

Ayrıca, okunabilirliğe yardımcı olmak için makro NULLbaşlık dosyasında bulunur stddef.h. Derleyicinize bağlı olarak aşağıdakileri yapmak mümkün olabilir:#undef NULL tuhaf bir şeye yeniden tanımlamak .

Bu nedenle, boş bir işaretçiyi kontrol etmenin bazı geçerli yolları şunlardır:

if (pointer == NULL)

NULLbir boş göstergeye eşit karşılaştırmak için tanımlanır. NULLGeçerli bir boş işaretçi sabiti olduğu sürece , gerçek tanımının ne olduğu tanımlanmış bir uygulamadır .

if (pointer == 0)

0 null işaretçi sabitinin başka bir temsilidir.

if (!pointer)

Bu if ifade "0 değil" örtük olarak kontrol eder, bu nedenle "0" anlamına gelmesini tersine çeviririz.

Boş gösterici olup olmadığını kontrol etmek için GEÇERSİZ yöntemler şunlardır:

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

Derleyici için bu bir boş gösterici için bir denetim değil, iki değişken üzerinde bir eşitlik denetimi. Bu olabilirMynull kodda hiçbir zaman değişmezse ve derleyici optimizasyonları sabit değeri 0 ifadesini if ​​ifadesine katlarsa yarayabilir, ancak bu garanti edilmez ve derleyicinin C Standardına göre en az bir tanı mesajı (uyarı veya hata) üretmesi gerekir.

C dilinde null işaretçi olduğunu unutmayın. Temel mimaride önemli değil. Temel mimarinin 0xDEADBEEF adresi olarak tanımlanan bir boş işaretçi değeri varsa, bu karmaşayı sıralamak derleyiciye kalmıştır.

Bu nedenle, bu komik mimaride bile, aşağıdaki yollar boş bir işaretçiyi kontrol etmek için hala geçerli yollardır:

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

Boş gösterici olup olmadığını kontrol etmek için GEÇERSİZ yöntemler şunlardır:

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

çünkü bunlar bir derleyici tarafından normal karşılaştırmalar olarak görülür.

Boş Karakterler

'\0'null bir karakter olarak tanımlanır - bu, tüm bitlerin sıfıra ayarlandığı bir karakterdir. Bunun işaretçilerle bir ilgisi yok. Ancak bu koda benzer bir şey görebilirsiniz:

if (!*string_pointer)

dize işaretçisinin boş bir karakteri gösterip göstermediğini kontrol eder

if (*string_pointer)

dize işaretçisinin boş olmayan bir karakteri gösterip göstermediğini kontrol eder

Bunları boş göstericilerle karıştırmayın. Sadece bit temsili aynı olduğundan ve bu durum bazı uygun çapraz geçişlere izin verdiği için, gerçekten aynı şey değildir.

Ayrıca, '\0'(tüm karakter değişmezleri gibi) bir tamsayı sabiti, bu durumda sıfır değeri ile. Yani '\0'tamamen süslenmemiş bir 0tamsayı sabitine eşdeğerdir - tek fark, bir insan okuyucuya iletme niyetindedir ("Bunu boş karakter olarak kullanıyorum").

Referanslar

Daha fazla bilgi için comp.lang.c SSS'nin 5.3 bölümüne bakın . C standardı için bu pdf'ye bakın . 6.3.2.3 İşaretçiler, paragraf 3 bölümlerine bakın.


3
SSS listesine yönlendirdiğiniz için teşekkür ederiz. Ancak, ayrıca bkz. C-faq.com/null/nullor0.html
Sinan Ünür

4
Hayır, karşılaştırmak olmaz ptrüzere bütün bitlik sıfır . Bu bir değil memcmp, ancak yerleşik bir işleç kullanılarak yapılan bir karşılaştırmadır. Bir tarafı boş bir işaretçi sabiti '\0', diğer tarafı bir işaretçi. Ve diğer iki versiyonda olduğu gibi NULLve 0. Bu üçü de aynı şeyi yapıyor.
Johannes Schaub - litb

6
Yerleşik karşılaştırma işlecini bit dizelerini karşılaştıracak bir şey olarak alıyorsunuz. Ama öyle değil. Soyut kavramlar olan iki değeri karşılaştırır. Olarak temsil edilir olduğu bir boş gösterici Yani 0xDEADBEEFhala bir boş gösterici onun Bit dizisi bakışlar gibi ne olursa olsun, ve hala eşit karşılaştırır NULL, 0, \0ve diğer tüm boş işaretçi sabit formlar.
Johannes Schaub - litb

2
Karşılaştırma operatörü hakkında iyi bir noktaya değindiniz. C99'u fırçaladım. "0 değerine sahip bir tamsayı sabit ifadesine veya void * türüne dökülen böyle bir ifadeye boş gösterici sabiti denir." Ayrıca, bir karakter değişmezinin tamsayı sabit bir ifade olduğunu söylüyor. Böylece, geçişli mülkiyet tarafından haklısınız ptr == '\0'.
Andrew Keeton

2
“.... NULL #def yapmak ve onu tuhaf bir şeye yeniden tanımlamak mümkün olabilir. Bunu yapan herkes vurulmayı hak eder.” Bu benim iyi efendim beni yüksek sesle güldürdü ...
oggiemc

34

Bazı insanlar NULL, '\ 0' ve 0 arasındaki farkların ne olduğunu yanlış anlıyorlar. Yani, açıklamak ve daha önce söylenen şeyleri tekrarlamaktan kaçınmak için:

int0 değerine sahip bir tür sabit ifadesi veya türüne dönüştürülen bu tür bir ifade, bir işaretçiye dönüştürüldüğünde boş bir işaretçi haline gelen void *bir boş işaretçi sabitidir . Standart tarafından herhangi bir işaretçiye eşit olmayan herhangi bir nesne veya işlevin karşılaştırılması garanti edilir .

NULLbir boş gösterici sabiti olarak tanımlanan bir makrodur .

\0null karakteri temsil eden bir yapıdırbir dizeyi sonlandırmak için kullanılan .

Bir boş karakter 0 olarak ayarlanır, tüm bit olan byte'tır.


14

Her üçü de sıfırın anlamını farklı bağlamlarda tanımlar.

  • işaretçi içeriği - NULL kullanılır ve işaretçinin değeri 32 bit mi yoksa 64 bit mi olmasından bağımsız olarak 0'dır (bir vaka 4 diğer 8 bayt sıfır).
  • dize bağlamı - sıfır basamağını temsil eden karakterin onaltılık değeri 0x30 iken, NUL karakterinin onaltılık değeri 0x00'dür (dizeleri sonlandırmak için kullanılır).

Belleğe baktığınızda bu üçü her zaman farklıdır:

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

Umarım bu açıklığa kavuşur.


8
Nasko: Değerlendirin sizeof('\0')ve şaşırın .
caf

3
@Nasko: Gerçekten şaşırdım: gcc ile, C: sizeof ('\ 0') == sizeof ('a') == 4, g ++ ile, C ++ ile: sizeof ('\ 0') == sizeof ('a') == 1
David Rodríguez - dribeas

1
@Nasko: C standardından (taslak, n1124): 'Bir tamsayı karakter sabiti int türüne sahiptir, bu nedenle' \ 0 'aslında C türünde int türündedir ve bu nedenle mimarimde sizeof (' \ 0 ') 4'tür. (linux, 32bit)
David Rodríguez - dribeas

@dribeas - Bunu sabit olarak tanımlamıyordum, dizenin bir parçası olarak göreceğiniz şeyi. Kesinlikle açık yapabilirdim. Teşekkürler
Nasko

@ DavidRodríguez-dribeas Undid düzenlemek "Düzeltildi '0' ASCII değeri 0x20 (32
aralık

6

NULL ve 0 null işaretçi sabitleri ile eşdeğerse, hangisini kullanmalıyım? C SSS listesinde de bu sorun ele alınmaktadır:

C programcıları bunu anlamalı NULLve 0işaretçi bağlamlarında değiştirilebilir ve bir noktalama işareti 0 mükemmel kabul edilebilir. Herhangi bir NULL kullanımı (aksine 0) bir işaretçinin dahil olduğunu nazik bir hatırlatma olarak düşünülmelidir; programcılar işaretçileri 0tamsayılardan ayırmak için ona (kendi anlayışları veya derleyicileri için) güvenmemelidir 0.

Sadece işaretçi bağlamında NULLve 0eşdeğerdir. çalışmasına rağmen NULLbaşka bir tür 0gerekli olduğunda kullanılmamalıdır , çünkü böyle yapmak yanlış stilistik mesaj gönderir. (Ayrıca, ANSI tanımını sağlar NULLolmak ((void *)0)Özellikle, kullanmayan olmayan işaretçi bağlamlarda hiç olmayan çalışma. Olacak) NULLGeçersiz ASCII karakter (zaman NUL) arzu edilir. Kendi tanımınızı girin

#define NUL '\0'

Gerekirse.


5

NULL, '\ 0' ve 0 arasındaki fark nedir

"null karakter (NUL)" ekarte etmek en kolay yoldur. '\0'bir karakter değişmezidir. C olarak int, yani 0 ile aynı olan uygulanır INT_TYPE_SIZE. C ++ 'da, karakter değişmez chardeğeri 1 bayt olarak uygulanır. Bu normalde NULLveya ' dan farklıdır 0.

Daha sonra NULL, bir değişkenin herhangi bir adres alanına işaret etmediğini belirten bir işaretçi değeridir. Genellikle sıfır olarak uygulandığı gerçeğini bir kenara bırakırsak, mimarinin tüm adres alanını ifade edebilmelidir. Bu nedenle, 32 bit mimaride NULL (büyük olasılıkla) 4 bayt ve 64 bit mimaride 8 bayttır. Bu C'nin uygulanmasına bağlıdır.

Son olarak, hazır 0tiptedir intboyutu, INT_TYPE_SIZE. Varsayılan değeri INT_TYPE_SIZEmimariye bağlı olarak farklı olabilir.

Apple şunu yazdı:

Mac OS X tarafından kullanılan 64 bit veri modeli "LP64" olarak bilinir. Bu, Sun ve SGI'nin diğer 64 bit UNIX sistemlerinin yanı sıra 64 bit Linux tarafından kullanılan yaygın veri modelidir. LP64 veri modeli ilkel türleri aşağıdaki gibi tanımlar:

  • ints 32 bit
  • uzunlukları 64 bit
  • uzun-uzunluklar da 64-bit
  • işaretçiler 64 bit

Wikipedia 64 bit :

Microsoft'un VC ++ derleyicisi LLP64 modelini kullanır.

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       ?

Düzenleme : Karakter değişmezine daha fazla eklendi.

#include <stdio.h>

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

Yukarıdaki kod gcc'de 4, g ++ üzerinde 1 döndürür.


2
Hayır, '\0'bir değil bir 1 bayt değeri. Bir tamsayı sabit ifadesi olan bir karakter değişmezidir - eğer bir boyuta sahip olduğu söylenebilirse, o zaman bir int(en az 2 bayt olması gerekir) boyutudur. Bana inanmıyorsanız, sizeof('\0')kendiniz değerlendirin ve görün. '\0', 0Ve 0x0tüm tamamen eşdeğerdir.
caf

@caf dile bağlıdır. Bana inanmıyorsanız sizeof('\0'), bir C ++ derleyicisini deneyin .
Eugene Yokota

2
sizeof (bir şey) yazdırırken "% zu" kullanmalısınız
Kullanılmayan


4

C ile başlarken bana yardımcı olan iyi bir parça (Linden tarafından Uzman C Programlamasından alınmıştır)

Bir 'l' boş ve İki 'l' boş

İşaretçiler ve ASCII sıfır için doğru terminolojiyi hatırlamak için bu küçük kafiyeyi ezberleyin:

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. 

Sıfır bit desenine sahip ASCII karakteri "NUL" olarak adlandırılır. İşaretçi noktalarının hiçbir yerde olmadığı anlamına gelen özel işaretçi değeri "NULL". İki terimin anlamı birbirinin yerine kullanılamaz.


Çok daha basit: NULörneğin bir kontrol kodu BEL, VT, HT, SOTvb ve böylece maksimum vardır. 3 karakter.
glglgl

2

"NUL" 0 değildir, ancak ASCII NUL karakterini belirtir. En azından, bu şekilde kullanıldığını gördüm. Boş gösterici genellikle 0 olarak tanımlanır, ancak bu, içinde çalıştığınız ortama ve kullandığınız işletim sisteminin veya dilin özelliklerine bağlıdır.

ANSI C'de, boş işaretçi 0 tamsayı değeri olarak belirtilir. Bu nedenle, doğru olmayan herhangi bir dünya ANSI C uyumlu değildir.


1

Değeri olan bir bayt 0x00, ASCII tablosunda NULveya adlı özel karakterdir NULL. C'de, kontrol karakterlerini kaynak kodunuza gömmemeniz gerektiğinden, bu, çıkış 0 değeri olan C dizelerinde gösterilir, yani,\0 .

Ama gerçek bir NULL değil değer . Bu bir değerin olmamasıdır. İşaretçi için, işaretçinin göstereceği hiçbir şey olmadığı anlamına gelir. Bir veritabanında, bir alanda değer olmadığı anlamına gelir (alanın boş, 0 veya boşluklarla dolu olduğunu söylemekle aynı şey değildir).

Gerçek değer verilen bir sistem veya veritabanı dosya biçimi kullanır bir temsil etmekNULL ille değildir 0x00.


0

NULL0 olduğu garanti edilmez - kesin değeri mimariye bağlıdır. Büyük mimarilerin çoğu bunu tanımlamaktadır (void*)0.

'\0' her zaman 0'a eşit olacaktır, çünkü byte 0 bir karakter değişmezinde bu şekilde kodlanır.

C derleyicilerinin ASCII kullanması gerekip gerekmediğini hatırlamıyorum - eğer değilse, '0'her zaman eşit olmayabilir 48. Yine de, çok fazla çalışmadığınız sürece EBCDIC gibi alternatif bir karakter seti kullanan bir sistemle karşılaşmanız pek olası değildir karanlık sistemler.

Çeşitli türlerin boyutları 64 bit sistemlerde farklılık gösterir, ancak tamsayı değerleri aynı olacaktır.


Bazı Commenters BOŞ 0'a eşit olduğu, ancak ifade şüphe var olabilir sıfır. İşte böyle bir sistemde beklenen çıktı ile birlikte örnek bir program:

#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;
}

Bu program yazdırabilir:

NULL == 0
NULL = 0x00000001

2
OP '0' (sıfır karakteri) değil '\ 0' (NUL karakteri) hakkında soruyordu
Chris Lutz

2
@Chris: '\ 0' NULL değil, bir karakter değişmezinde sekizlik olarak kodlanmış bayt 0'dır.
John Millikin

2
C ++ 'da, standart, 0 tam sayı değerinden bir işaretçiye dönüştürmenin her zaman boş bir işaretçi vereceğini garanti eder. C ++ 'da 0'ın boş gösterici olduğu garanti edilirken, diğer taraftan NULL bir makrodur ve kötü amaçlı bir kodlayıcı bunu farklı bir şey olarak yeniden tanımlayabilir.
David Rodríguez - dribeas

6
Ve NULL değerinin 0 olması garanti edilir. NULL işaretçisinin bit örüntüsünün tümüyle sıfır olması garanti edilmez, ancak NULL sabiti 0'dır ve her zaman 0 olacaktır.
jalf

2
İlk cümleniz yanlış - NULL, C ++ 'da (void *) 0 olarak tanımlanamaz çünkü bir void'den başka bir işaretçiye (C'den farklı olarak) örtük bir dönüştürme yoktur.

-2

(void *) 0 NULL ve '\ 0' bir dizenin sonunu temsil eder.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.