Önce veya sonra const?


146

Başlamak için muhtemelen constbir nesnenin verilerini veya değiştirilemeyen bir işaretçiyi veya her ikisini birden yapmak için kullanılabileceğini biliyorsunuzdur .

const Object* obj; // can't change data
Object* const obj; // can't change pointer
const Object* const obj; // can't change data or pointer

Ancak sözdizimini de kullanabilirsiniz:

Object const *obj; // same as const Object* obj;

Önemli görünen tek şey, yıldız işaretinin hangi tarafını constanahtar kelimeyi koyduğunuzdur . Şahsen ben constsoldan sağa zihnimde daha iyi okuduğunu ama daha önce hangi sözdizimi geldiğini bulmak gibi veri değiştirilemez belirtmek için tür sol koymak tercih ederim.

Daha da önemlisi, constveriyi belirtmek için neden iki doğru yol vardır ve varsa hangi durumda diğerini tercih edersiniz veya hangisine ihtiyacınız vardır?

Düzenle:

Demek ki, derleyicilerin bir şeyi nasıl yorumlamaları gerektiği standardı ben doğmadan çok önce hazırlanmışsa, bu keyfi bir karardı. Beri constsanırım anahtar kelimenin sol ne uygulanır (varsayılan olarak?) Onlar hiçbir zarar ekleyerek orada olduğunu düşündüm "kısayolları" beyanı ile değiştirir gibi bir zamana kadar en azından başka şekillerde kelime ve tip eleme uygulamak * veya &

Ben de sanırım C de böyle oldu?


9
Makrolar daima eklemek const sonra örneğin, tip #define MAKE_CONST(T) T constyerine #define MAKE_CONST(T) const T, böylece MAKE_CONST(int *)doğru genişleyecek int * constyerine const int *.
jotik

7
Bu iki üslubu "doğu const" ve "batı const" olarak adlandırdım.
Tom Anderson

14
@TomAnderson ama gerçekten "doğu const" ve "const batı" olmalıdır.
YSC

Yanıtlar:


96

constveriyi belirtmek için neden iki doğru yol vardır ve hangi durumda varsa diğerini tercih etmelisiniz ya da hangisine ihtiyacınız var?

Esasen, constbir yıldız işaretinden önce belirteçlerin içindeki konumunun önemli olmasının nedeni , C dilbilgisinin Kernighan ve Ritchie tarafından bu şekilde tanımlanmasıdır.

Dilbilgisini bu şekilde tanımlamalarının nedeni, C derleyicilerinin girdiyi soldan sağa ayrıştırması ve her jetonu tüketirken işlemeyi bitirmiş olmasıydı. Simgeyi kullanmak, *geçerli bildirimin durumunu bir işaretçi türüne dönüştürür. constSonra karşılaşma niteleyici bir işaretçi bildirimine uygulanır *anlamına gelir const; *vasıtanın işaret edilmeden önce belirtildiği verilere uygulandığı anlamına gelir.

Niteleyici consttür belirticilerinden önce veya sonra görünürse anlamsal anlam değişmediğinden , her iki şekilde de kabul edilir.

İşlev işaretçileri bildirilirken benzer bir durum ortaya çıkar, burada:

  • void * function1(void)geri dönen bir işlevi bildirir void *,

  • void (* function2)(void)dönen bir işleve bir işlev işaretçisi bildirir void.

Yine fark edilmesi gereken şey, dil sözdiziminin soldan sağa bir ayrıştırıcıyı desteklemesi.


7
Kernighan kitabı birlikte yazdı, ancak C'nin tasarımıyla ilgilenmedi, sadece Ritchie.
Tom Zych

8
Hangisinin hangisi olduğunu asla hatırlayamadım. Açıklamanız sayesinde nihayet hatırlamak için mnemoteknik var. Teşekkürler! *Derleyici ayrıştırıcı işaretçi olduğunu bilmeden önce veri değeri için sabittir. * İşaretinden sonra sabit ibre ile ilgilidir. Parlak. Ve son olarak neden yapabileceğimi const charde açıklıyor char const.
Vit Bernatik

2
Neden bu şekilde yapıldığına dair tahmin benim için oldukça zayıf / kendiyle çelişkili görünüyor. Yani, bir dili tanımlayıp bir derleyici yazıyorsam ve bunu basit tutmak ve "soldan sağa girişi ayrıştırmak ve her jetonu tükettiği şekilde işlemeyi bitirmek" istedim, dediğin gibi, bana öyle geliyor ki Ben consther zaman nitelendirdiği şeyden sonra gelmesini gerektirir ... tam olarak böylece her zaman tükettikten hemen sonra const işlemeyi bitirebiliriz. Yani bu batı-const'u yasaklamak için izin vermek yerine bir argüman gibi görünüyor .
Don Hatch

3
"Sabit niteleyici tür belirticilerinden önce veya sonra görünürse anlamsal anlam değişmediğinden, her iki şekilde de kabul edilir." Bu dairesel akıl yürütme değil mi? Soru şu ki, anlambilimsel anlam neden bu şekilde tanımlanıyor, bu yüzden bu cümlenin hiçbir şeye katkıda bulunduğunu düşünmüyorum.
Don Hatch

1
@donhatch Hatırlamak zorundasınız ki, günümüze ve iyi programlama dili tasarımına aşina olduğumuza göre yaptığımız varsayımlara göre, diller o zamanlar oldukça yeni şeylerdi. Ayrıca, dilin izinli veya kısıtlı bir dili olup olmadığı bir değer yargısıdır. Örneğin, python'un bir ++operatörü olmalı mı? "Cümle", imho, yapabileceğinden başka özel bir neden olmadığını anlamama yardımcı oldu. Belki bugün farklı bir seçim yaparlardı, belki de yapmazlardı.
ragerdl

75

Kural şöyledir:

const, geriye kalan şey için geçerlidir. Solda hiçbir şey yoksa, o zaman onun sağındaki şey için geçerlidir.

Ben const "orijinal" yolu tanımlanmış olduğu için const olmak şey sağındaki const kullanmayı tercih ediyorum.

Ama bence bu çok öznel bir bakış açısı.


18
Onu sola koymayı tercih ediyorum, ama bence sağa koymak daha mantıklı. Genellikle C ++ 'da türleri sağdan sola okursunuz, örneğin Object const *bir const Object nesnesine bir işaretçi. Eğer constsola koyarsanız, çok iyi akmayan sabit bir Nesneye işaretçi olarak okunacaktır.
Collin Dauphinee

1
Sol tarafta, diğer C bildirimleriyle insan tarzı tutarlılık olduğu izlenimi altındayım (bilgisayar constsınıfı açısından bir depolama sınıfı olmadığı için doğru değildir, ancak insanlar ayrıştırıcı değildir).
geekosaur

1
@Heath bunun bir kuraldan çok bir rehber olduğuna inanıyorum ve bunu derleyicinin nasıl yorumlayacağını hatırlamanın bir yolu olarak duydum ... Nasıl çalıştığını anlıyorum, bu yüzden sadece arkasındaki düşünce sürecini merak ettim her iki şekilde de destekleme kararı.
AJG85

3
@HeathHunnicutt kural var, ama biraz daha karmaşık: c-faq.com/decl/spiral.anderson.html
imallett

2
@HeathHunnicutt: spiral kuralı, ilk yorumcunun "Genel olarak sağdan sola [C /] C ++ 'da türleri okursunuz" yorumunun genişletilmiş sürümüdür. Sanırım bununla çelişiyordun. Ancak, bunun yerine cevabın kendisine atıfta bulunmuş olabileceğinizi düşünüyorum.
imallett

57

İkinci sözdizimini tercih ederim. Sağdan sola tip bildirimini okuyarak 'neyin' sabit olduğunu takip etmeme yardımcı olur:

Object * const obj;        // read right-to-left:  const pointer to Object
Object const * obj;        // read right-to-left:  pointer to const Object
Object const * const obj;  // read right-to-left:  const pointer to const Object

3
Kesinlikle. "Sabit bir nesneye sabit bir işaretçi" Object const* constdeğildir const const Object*. "const", pek çok insanın kesinlikle sevdiği özel durum dışında solda olamaz. (Yukarıdaki Heath'e bakınız.)
cdunn2001

38

Bir deklarasyondaki anahtar kelimelerin sırası bu kadar sabit değildir. "Tek bir gerçek düzene" birçok alternatif var. Bunun gibi

int long const long unsigned volatile i = 0;

ya da olmalı

volatile unsigned long long int const i = 0;

??


25
Basit bir değişkenin tamamen kafa karıştırıcı bir tanımı için +1. :)
Xeo

@rubenvb - Evet, ne yazık ki öyleler. Dilbilgisi sadece a'nın s decl-specifier-seqdizisi olduğunu söylüyor decl-specifier. Dilbilgisi tarafından verilen bir düzen yoktur ve her bir anahtar kelime için gerçekleşme sayısı yalnızca bazı semantik kurallarla sınırlıdır (bir constancak iki tane olabilir long:-)
Bo Persson

3
@rubenvb - Evet, unsignedbir tür ile aynıdır unsigned intve int unsigned. unsigned longdiğer bir tip, aynı unsigned long intve int long unsigned. Deseni görüyor musunuz?
Bo Persson

2
@Bo: Ortalığı görüyorum, bir model görmek için üç tane olmalı ;). Tamam, teşekkürler
rubenvb

1
Eskiden statickelimelerin karmakarışıklığını ekleyebildiniz , ancak sadece son zamanlarda önce staticgelmesi gereken derleyicilerden şikayet ettiniz .
Mark Lakata

8

İlk kural, yerel kodlama standartlarınızın gerektirdiği formatı kullanmaktır. Bundan sonra: constön tarafa koymak, typedef'ler söz konusu olduğunda karışıklığın sona ermesine yol açmaz, örneğin:

typedef int* IntPtr;
const IntPtr p1;   // same as int* const p1;

Kodlama standardınız typedef'lerin işaretçilere izin vermesi durumunda, türün ardından const koymak konusunda ısrarcı olmalıdır. Her durumda, ancak tipe uygulandığında, const ne için geçerli olduğunu takip etmelidir, bu nedenle tutarlılık da sonradan const lehine tartışır. Ancak yerel kodlama yönergeleri tüm bunları gölgede bırakır; fark normalde geri dönüp mevcut kodun tümünü değiştirecek kadar önemli değildir.


Bu dükkanda oldukça gevşek tanımlanmış standartlarımızda işaretçilerin tip tanımlarının olmamasının nedenini vurgulayabileceğini düşünüyorum .
AJG85

1
Benim politikası (yalnız karar vermek olsun) sonra (tutarlılık uğruna) const koymaktır ve (çok genel olarak ya typedefs) işaretçiler typedefs kullanmamayı :-). BTW, string :: iterator vs. string :: const_iterator da muhtemelen kararınıza dahil edilmelidir. (Sadece bir şeyler karıştırmak için :-). Doğru cevap yok.)
James Kanze

Ah evet const std::string::const_iteratoriyi önlem için de davranış dahil olabilir ;)
AJG85 20

2
@JamesKanze - Bir dakika, burada bana yardım et ... Yayınlanan örnekte karışıklığı görmüyorum. const IntPtr p1"Sabit tamsayı işaretçisi" (yani, "tamsayıya tamsayı") dışında başka ne anlama gelir? Doğru zihninde hiç kimse, nasıl IntPtrtanımlandığını bilmese bile , bunun p1değişebilir olduğunu düşünmezdi . Ve bu nedenle, neden yanlış *p1olanın değişmez olduğunu varsayalım ? Dahası, const'i başka bir yere koymak (örneğin, IntPtr const p1) semantiği hiç değiştirmez.
Todd Lehman

3
@ToddLehman Karışıklık görmeyebilirsiniz, ancak çoğu C ++ programcısı bunu yapar ve sistematik olarak yanlış anlar (şüphe yok ki std::vector<T>::const_iterator, const olan yineleyici değil, ama neyi işaret ettiği gibi şeylerin yardım ettiği ).
James Kanze

7

Sol ya da sağın kabul edilebilir olmasının tarihsel nedenleri vardır. Stroustrup, 1983'e kadar C ++ 'a const ekledi , ancak C89 / C90'a kadar C'ye yapmadı.

C ++ 'da her zaman sağda const kullanmak için iyi bir neden vardır. Sabit üye işlevlerinin şu şekilde bildirilmesi gerektiği için her yerde tutarlı olacaksınız :

int getInt() const;

1
... iyi, "iyi neden" o kadar inandırıcı değil, çünkü "const" için olası diğer konumlar aynı şey demek değildir. const int& getInt(); int& const getInt();
Maestro

1
@Maestro: Ben karşılık gelen int const& getInt();daha iyidir, const int& getInt();ancak int& const getInt();karşılaştırmak yasal (referansları zaten const) gereksizdir ve genellikle bir uyarı verecektir. Her neyse, üye işlevindeki const işlevdeki thisişaretçiyi yerine olarak Foo* constdeğiştirir Foo const* const.
Nick Westgate

constüye işlevi aynı anlama gelmez - veya void set(int)&;bir işleve bir tür referans mıdır?
Davis Herring
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.