0 değerini ikame olarak NULL kullanabilir miyim?


73

NULLİşaretçiyi, değerinin yerine kullanmam için kullanabilir miyim 0?

Yoksa bununla ilgili yanlış bir şey mi var?


Mesela, örneğin:

int i = NULL;

yedek olarak:

int i = 0;

Deney olarak aşağıdaki kodu derledim:

#include <stdio.h>

int main(void)
{
    int i = NULL;
    printf("%d",i);

    return 0;
}

Çıktı:

0

Nitekim bana tamamen doğru olan bu uyarıyı veriyor:

warning: initialization makes integer from pointer without a cast [-Wint-conversion] 

ancak sonuç hala eşdeğerdir.


  • Bununla "Tanımsız Davranış" a geçiyor muyum?
  • NULLBu şekilde kullanılmasına izin veriliyor mu?
  • NULLAritmetik ifadelerde sayısal değer olarak kullanmanın yanlış bir yanı var mı ?
  • Peki bu durum için C ++ 'da sonuç ve davranış nedir?

Ben cevaplarını okumak zorunda '\ 0', NULL arasındaki fark nedir ve 0 arasındaki fark nedir hakkında NULL, \0ve 0bunun doğru kullanımına da oldukça caizdir ve eğer, ama oradan özlü bilgi alamadım NULLolarak ödevlerde ve diğer aritmetik işlemlerde kullanılacak değer.


Yorumlar uzun tartışmalar için değildir; bu sohbet sohbete taşındı .
Samuel Liew

Biri C ve diğeri C ++ için iki ayrı soru sormak gerçekten daha iyi olurdu.
Konrad Rudolph

Yanıtlar:


82

0 değerinin yerine NULL işaretçisini kullanmama izin veriliyor mu?

Hayır , bunu yapmak güvenli değil. NULL, tipe sahip olabilenint , ancak daha tipik olarak tipte void *(C cinsinden) olan veya başka bir şekilde doğrudan int(C ++> = 11'de) atanamayan bir boş gösterici sabitidir . Her iki dil de işaretçilerin tamsayılara dönüştürülmesine izin verir, ancak bu tür dönüşümlerin örtülü olarak gerçekleştirilmesini sağlamaz (bazı derleyiciler bunu bir uzantı olarak sağlar). Ayrıca, 0 değerini vermek için bir boş göstergeyi bir tam sayıya dönüştürmek yaygın olsa da, standart bunu garanti etmez. Tür intve değer 0 olan bir sabit istiyorsanız, heceleyin 0.

  • Bununla Tanımsız Davranışlara geçebilir miyim?

Evet, NULLtürü olan bir değere void *veya doğrudan atanamayan herhangi bir değere genişleyen herhangi bir uygulamada int. Standart, ödevinizin bu tür bir uygulamadaki davranışını tanımlamaz, davranışı tanımlanmamıştır.

  • NULL ile bu şekilde çalışmasına izin veriliyor mu?

Kötü bir stil ve bazı sistemlerde ve bazı durumlarda kırılacak. GCC kullanıyor gibi göründüğünüz gibi, seçenekle derlerseniz kendi örneğinizde kırılacaktır -Werror.

  • Aritmetik ifadelerde NULL değerini sayısal değer olarak kullanmak yanlış mı?

Evet. Sayısal bir değere sahip olduğu garanti edilmez. 0'ı kastediyorsanız, sadece iyi tanımlanmış değil, daha kısa ve daha net olan 0 yazın.

  • Ve bu durumda C ++ sonucu nasıl?

C ++ dili dönüşümler konusunda C'den daha katıdır ve farklı kurallara sahiptir NULL, ancak uygulamalar da uzantılar sağlayabilir. Yine, 0 demek istiyorsanız, yazmanız gereken şey budur.


4
"Daha tipik olarak türü olan void *" ın yalnızca C için geçerli void *olduğunu belirtmeniz gerekir void*. C ++ 89 ve C ++ 03 yılında aslında NULL gerekir tipte int, ancak daha sonraki sürümlerde olması (ve genellikle) olabilir nullptr_t.
Martin Bonner,

Ayrıca yanlış dönüştürme void*için inttanımsız davranıştır. O değil; uygulama tarafından belirlenen davranıştır.
Martin Bonner,

@MartinBonnersupportsMonica, C'nin bir işaretçinin bir tamsayıya dönüştürüldüğünü belirlediği bağlamlarda, dönüşümün sonucu gerçekten uygulama tarafından belirtilir, ancak bahsettiğim şey bu değildir. Tanımlanmamış davranışa sahip bir tamsayı türüne (açıkça bir döküm yoluyla dönüştürmeden) bir işaretçiye atanmasıdır. Dil, burada otomatik bir dönüşüm tanımlamaz.
John Bollinger

@MartinBonnersupportsMonica, C ++ konularında daha kapsayıcı olacak şekilde düzenledim. Her durumda, merkezi tema her iki dile eşit olarak uygulanır: 0 tamsayısı istiyorsanız, açıkça uygun türde bir tamsayı sabiti olarak yazın.
John Bollinger

31

NULLboş bir işaretçi sabiti. C'de, değeri olan bir tamsayı sabit ifadesi 0ya da böyle bir ifade void*, ikincisi daha olasıdır. Hangi anlamına olamaz kullanmak farz NULLsıfır ile birbirlerinin yerine. Örneğin, bu kod örneğinde

char const* foo = "bar"; 
foo + 0;

İki işaretçi (farklı işaretçi türlerinin yanı sıra) arasında ekleme tanımlanmadığı için 0ile değiştirmenin NULLgeçerli bir C programı olması garanti edilmez. Bir sınırlama ihlali nedeniyle teşhis yapılmasına neden olur. Eklenecek işlenenler geçerli olmayacak .


C ++ 'a gelince, işler biraz farklıdır. void*Diğer nesne türlerine örtük dönüşüm olmaması NULL, geçmişte 0C ++ kodunda tanımlandığı anlamına geliyordu . C ++ 03'te muhtemelen bundan kurtulabilirsiniz. Ancak C ++ 11'den beri yasal olarak nullptranahtar kelime olarak tanımlanabilir . std::nullptr_tİşaretçi türlerine eklenemeyebileceğinden , şimdi tekrar bir hata üretiyoruz .

Eğer NULLolarak tanımlanır nullptrsonra bile denemeniz geçersiz olur. std::nullptr_tKonumundan tamsayıya dönüşüm yok . Bu yüzden daha güvenli bir boş gösterici sabiti olarak kabul edilir.


Tamlık için, 0L aynı zamanda bir boş işaretçi sabitidir ve NULLher iki dilde de kullanılabilir .
eerorika

1
@jamesqf Standart, 0 değerine sahip tamsayı sabitinin boş bir işaretçi sabiti olduğunu söyler. Bu nedenle 0L, boş bir işaretçi sabiti.
eerorika

1
@eerorika: Dünyanın ihtiyacı olan şey, gerçeği görmezden gelen standartlar :-) 'Çünkü 80286 derlememi doğru hatırlıyorsam, tek bir işlem olarak uzak bir işaretçi bile atayamazsınız, bu yüzden derleyici yazarları özel -çözün.
jamesqf

2
@jamesqf SSS'ye göre , yeniden: 0bir boş gösterici sabit yapmak: "açıkça yanlış varsayımlar yapan tüm kötü yazılmış C koduna bir sop olarak"
Andrew Henle

3
@jamesqf, 0 değerine sahip her tamsayı sabitinin bir boş işaretçi sabiti (C cinsinden) olduğu, donanım işaretçisi uygulamalarıyla ilgisi yoktur. Ayrıca standart C'nin her durumda yakın ve uzak işaretçiler arasındaki farkı tanımadığını, ancak işaretçi-işaretçi atamalarını desteklediğini unutmayın. Ayrıca, 286'lar gibi bölümlenmiş adresleme formatları için ilginç sorunlar sunan işaretçi karşılaştırmalarını da (bazı) destekler.
John Bollinger

21

0 değerinin yerine NULL işaretçisini kullanmama izin veriliyor mu?

int i = NULL;

Kurallar diller ve sürümleri arasında farklılık gösterir. Bazı durumlarda yapabilir ve diğerlerinde yapamazsınız. Ne olursa olsun, yapmamalısın . Eğer şanslıysanız, derleyiciniz denediğinizde veya daha da iyisi derleme konusunda uyarır.

C ++ 'da, C ++ 11'den önce (C ++ 03'ten alıntı):

[Lib.support.types]

NULL, bu Uluslararası Standartta uygulama tanımlı bir C ++ null işaretçi sabiti.

Bir tamsayı olarak bir boş gösterici sabiti kullanmak çok mantıklı değildir. Ancak...

[Conv.ptr]

Bir boş işaretçi sabiti, sıfıra olarak değerlendirilen tamsayı türünün bir integral sabit ifade (5.19) değeridir.

Yani, saçma olsa bile teknik olarak işe yarayacaktı. Bu teknik nedeniyle, kötüye kullanan kötü yazılmış programlarla karşılaşabilirsiniz NULL.

C ++ 11'den beri (son taslaktan alıntı):

[Conv.ptr]

Bir boş gösterici sabit sıfır değerine sahip bir tam sayı değişmez ([lex.icon]) olduğu veya tip std bir prvalue :: nullptr_t .

A std​::​nullptr_­tbir tam sayıya dönüştürülemez, bu nedenle NULLtamsayı olarak kullanmak dil uygulamasının yaptığı seçimlere bağlı olarak yalnızca koşullu olarak çalışır.

PS nullptr, bir tür ön değerdir std​::​nullptr_­t. C ++ 11 öncesi derlemek için programa ihtiyacınız yoksa, nullptrbunun yerine her zaman kullanmalısınız NULL.


C biraz farklıdır (C11 taslak N1548'den alıntılar):

6.3.2.3 Dil / Dönüşümler / Diğer işlenenler / İşaretçiler

3 0 değerine sahip bir tamsayı sabit ifadesine veya türüne dökülen böyle bir ifadeyevoid * boş işaretçi sabiti denir. ...

Yani, durum C ++ 11 sonrası ile benzerdir, yani NULLdil uygulaması tarafından yapılan seçimlere bağlı olarak koşullu işlerin kötüye kullanılması .


10

Evet , ancak uygulamaya bağlı olarak bir kadroya ihtiyacınız olabilir . Ama evet,% 100 meşru, aksi halde.

Her ne kadar gerçekten, gerçekten, gerçekten kötü bir stil olmasına rağmen (söylemeye gerek yok mu?).

NULLolduğu, yoksa aslında C grubu ++ C. standart etmez birçok Cı miras için, iki maddeleri teknik yapmak ([diff.null] ve [support.types.nullptr]) var gibi, ancak NULLC ++. Bir olan uygulama tanımlı boş işaretçisi sabiti . Bu nedenle, kötü bir stil olsa bile, teknik olarak olabildiğince C ++.
İşaret edildiği gibi dipnot , olası uygulamalar olabilir 0ya 0Lama değil (void*)0 .

NULLTabii ki (standart açıkça söylemez, ancak hemen sonra 0veya kalan tek seçenek 0L) nullptr. Bu neredeyse hiç olmadı, ancak yasal bir olasılık.

Derleyicinin size gösterdiği uyarı, derleyicinin aslında uyumlu olmadığını gösterir (C modunda derlemediyseniz). Çünkü, uyarıya göre, bir boş gösterici dönüştürdü ( nullptrhangisi olmayacak nullptr_t, hangisi farklı olurdu), bu yüzden görünüşe göre tanımı NULLaslında (void*)0öyle olmayabilir.

Her iki durumda da, iki olası meşru (yani derleyici bozulmamış) durumunuz vardır. Ya (gerçekçi durum), ya da NULLgibi bir şeydir , o zaman tamsayıya "sıfır ya da bir" dönüşüm yaparsınız ve gitmekte fayda vardır.00L

Ya NULLda gerçekten nullptr. Bu durumda , tamsayılardan açıkça tanımlanmış dönüşümlerin yanı sıra karşılaştırma konusunda garantileri olan , ancak tam olarak tamsayılara karşı olmayan ayrı bir değere sahipsiniz . Bununla birlikte, açıkça tanımlanmış bir dönüşüme bool(sonuç olarak false) boolsahiptir ve açıkça tanımlanmış bir tam sayıya dönüşüme sahiptir (sonuç olarak 0).

Ne yazık ki, bu iki dönüşüm, bu yüzden [dönş.] İçinde belirtildiği gibi "sıfır veya bir" içinde değildir . Uygulamanız tanımlıyorsa Böylece NULLolarak nullptr, o zaman kod doğru olduğu için açık atması eklemek gerekir.


6

C SSS'den:

S: NULL ve 0 null işaretçi sabitleri ile eşdeğerse, hangisini kullanmalıyım?

C: Sadece işaretçi bağlamında NULLve 0eşdeğerdir. NULLgerektiğini değil 0 başka türlü gerektiğinde bu işe yarayabilecek olsa da bunu yaparken yanlış üslup mesaj gönderdiği için, kullanılabilir. (Dahası, ANSI, ((void *)0)işaretçi olmayan bağlamlarda hiç çalışmayacak olan NULL tanımının olmasına izin verir .) Özellikle NULLASCII null karakteri (NUL) istendiğinde kullanmayın. Kendi tanımınızı girin

http://c-faq.com/null/nullor0.html


5

Feragatname: C ++ bilmiyorum. Cevabım C ++ bağlamında uygulanacak değil

'\0'Bir olan intsadece% 100 gibi tam olarak, değer sıfır 0.

for (int k = 10; k > '\0'; k--) /* void */;
for (int k = 10; k > 0; k--) /* void */;

İşaretçiler bağlamında , 0ve NULL% 100 eşdeğerdir:

if (ptr) /* ... */;
if (ptr != NULL) /* ... */;
if (ptr != '\0') /* ... */;
if (ptr != 0) /* ... */;

hepsi% 100 eşdeğerdir.


Hakkında not ptr + NULL

Bağlamı ptr + NULLolan değil işaretçileri söyledi. C dilinde işaretçi eklemek için bir tanım yoktur; işaretçiler ve tamsayılar eklenebilir (veya çıkarılabilir). Gelen ptr + NULLya eğer ptryoksa NULLbir işaretçi olduğu, diğer olmalı , böylece bir tamsayı ptr + NULLetkili bir olduğunu (int)ptr + NULLya ptr + (int)NULLve tanımları bağlı ptrve NULLbirkaç davranışlar beklenebilir: hepsi çalışma, pointer ve tamsayı, derlemek başarısızlık arasındaki dönüşüm için uyarıda .. .


Daha önce gördüm #define NULL (void *)0. NULL ve plain 0 öğelerinin% 100 eşdeğer olduğundan emin misiniz?
machine_1

2
İşaretçi bağlamında, evet ...
cevabımda

@phuclv: C ++ hakkında hiçbir fikrim yok. Cevabım (parantez arasındaki bit hariç) yaklaşık C
pmg

@phuclv işaretçiler bağlamında ptr + NULLkullanmıyorNULL
pmg

3
@JesperJuhl: işaretçiler bağlamında % 100 eşdeğerdir. Ne olduğu hakkında hiçbir fikrim yok nullptrama ((void*)0)ve 0(veya '\0') işaretçiler bağlamında eşdeğer ...if (ptr == '\0' /* or equivalent 0, NULL */)
pmg

5

Hayır, artık tercih edilmiyor NULL(eski işaretçi başlatmanın yolu).

C ++ 11'den beri:

Anahtar kelime nullptrişaretçi değişmezi ifade eder. Std :: nullptr_t türünün bir önkoşuludur. nullptrHerhangi bir işaretçi türünün ve herhangi bir işaretçi ve üye türünün boş göstergesinden örtük dönüşümleri vardır . std::nullptr_tMakroda olduğu gibi tür değerlerini de içeren herhangi bir boş işaretçi sabiti için benzer dönüşümler vardır NULL.

https://en.cppreference.com/w/cpp/language/nullptr

Aslında, std :: nullptr_t , boş gösterici değişmezinin tipidir nullptr. Kendisi bir işaretçi türü veya üye türüne işaretçi olmayan farklı bir türdür.

#include <cstddef>
#include <iostream>

void f(int* pi)
{
   std::cout << "Pointer to integer overload\n";
}

void f(double* pd)
{
   std::cout << "Pointer to double overload\n";
}

void f(std::nullptr_t nullp)
{
   std::cout << "null pointer overload\n";
}

int main()
{
    int* pi; double* pd;

    f(pi);
    f(pd);
    f(nullptr);  // would be ambiguous without void f(nullptr_t)
    // f(0);  // ambiguous call: all three functions are candidates
    // f(NULL); // ambiguous if NULL is an integral null pointer constant 
                // (as is the case in most implementations)
}

Çıktı:

Pointer to integer overload
Pointer to double overload
null pointer overload

Soru, tamsayılar için NULL değerinin 0'a atanmasıyla ilgilidir. Bu anlamda, null yerine nullptr ile hiçbir şey değişmez.
ivan.ukr

Kelimeleri "BOŞ işaretçi" olarak kullandı.
Mannoj

Bu arada, C ++, C ++ 11'den sonra NULL konseptine sahip değildir. Yazar, constexpr kullanımı konusunda karışık olabilir veya eski yol başlatmayı tanımlayabilir. en.cppreference.com/w/cpp/language/default_initialization
Mannoj
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.