C ++ tanımlayıcısında alt çizgi kullanma ile ilgili kurallar nelerdir?


930

Yerel değişkenler veya parametreler yerine üye değişkenleri olduklarını belirtmek için üye değişkenlerini bir tür önekle adlandırmak C ++ 'da yaygındır. Bir MFC geçmişinden geldiyseniz muhtemelen kullanacaksınız m_foo. Ben de myFooara sıra gördüm .

C # (ya da sadece .NET) olduğu gibi, sadece bir alt çizgi kullanmanızı önerir _foo. Buna C ++ standardı izin veriyor mu?



6
Sadece bu kuralların cehaletinin mutlaka kodunuzun derlenmeyeceğini veya çalışmadığını ima etmediğini unutmayın, ancak kodunuzun farklı derleyiciler ve sürümlere taşınabilir olmayacağı muhtemeldir, çünkü ad olmayacağı garanti edilemez. çatışmalar. Bunu desteklemek için, adlandırma kuralı olarak her yerde _ büyük harf kullanan önemli bir sistemin kesin olarak uygulanmasını biliyorum. Orada hiçbir hata nedeniyle. Tabii ki kötü bir uygulama.
g24l

Yanıtlar:


852

C ++ 11'de değişmeyen kurallar:

  • Uygulama makroları olarak kullanılması da dahil olmak üzere her kapsamda saklıdır :
    • alt çizgi ile başlayan ve hemen büyük harfle başlayan tanımlayıcılar
    • bitişik alt çizgi içeren tanımlayıcılar (veya "çift alt çizgi")
  • Global ad alanında saklıdır:
    • alt çizgiyle başlayan tanımlayıcılar
  • Ayrıca, stdad alanındaki her şey saklıdır. (Bununla birlikte, şablon uzmanlıkları eklemenize izin verilir.)

2003 C ++ Standardından:

17.4.3.1.2 Genel adlar [lib.global.names]

Belirli adlar ve işlev imzaları her zaman uygulamaya ayrılmıştır:

  • Çift alt çizgi ( __) içeren veya alt çizgi ve ardından büyük harf (2.11) ile başlayan her ad, herhangi bir kullanım için uygulamaya ayrılmıştır.
  • Alt çizgi ile başlayan her ad, genel ad alanında ad olarak kullanılmak üzere uygulamaya ayrılmıştır. 165

165) Bu adlar ad alanında da saklıdır ::std(17.4.3.1).

C ++, C standardına (1.1 / 2, C ++ 03) dayandığından ve C99, normatif bir referans (1.2 / 1, C ++ 03) olduğundan, bunlar 1999 C Standardından da geçerlidir:

7.1.3 Ayrılmış tanımlayıcılar

Her başlık, ilişkili alt maddesinde listelenen tüm tanımlayıcıları bildirir veya tanımlar ve isteğe bağlı olarak, gelecekteki herhangi bir kitaplık yönlendirme alt maddesinde listelenen tanımlayıcıları veya her zaman kullanım için veya dosya kapsamı tanımlayıcıları olarak kullanılmak üzere ayrılmış tanımlayıcıları bildirir veya tanımlar.

  • Bir alt çizgi ve bir büyük harf veya başka bir alt çizgi ile başlayan tüm tanımlayıcılar her zaman her türlü kullanıma ayrılmıştır.
  • Alt çizgiyle başlayan tüm tanımlayıcılar, hem normal hem de etiket adı alanlarında dosya kapsamına sahip tanımlayıcılar olarak kullanılmak üzere her zaman ayrılır.
  • Aşağıdaki alt cümlelerin herhangi birindeki (gelecekteki kütüphane talimatları dahil) her makro adı, ilişkili üstbilgilerinden herhangi biri dahil edildiğinde belirtildiği şekilde kullanılmak üzere ayrılmıştır; aksi açıkça belirtilmedikçe (bkz. 7.1.4).
  • Aşağıdaki alt bölümlerden herhangi birinde harici bağlantılı tüm tanımlayıcılar (gelecekteki kitaplık yönergeleri dahil) her zaman harici bağlantılı tanımlayıcılar olarak kullanılmak üzere ayrılmıştır. 154
  • Aşağıdaki alt bölümlerden herhangi birinde listelenen dosya kapsamına sahip her tanımlayıcı (gelecekteki kitaplık yönergeleri dahil), makro adı olarak ve ilişkili üstbilgilerinden herhangi biri varsa, aynı ad alanında dosya kapsamına sahip bir tanımlayıcı olarak ayrılmıştır.

Başka tanımlayıcı ayrılmış değildir. Program, tanımlayıcıyı ayrıldığı bir bağlamda bildirir veya tanımlarsa (7.1.4'te izin verilenin dışında) veya ayrılmış bir tanımlayıcıyı makro adı olarak tanımlarsa, davranış tanımsızdır.

Program #undefyukarıda listelenen ilk gruptaki bir tanımlayıcının herhangi bir makro tanımını kaldırırsa (ile ), davranış tanımsız olur.

154) dış bağlantı ile ayrılmış tanımlayıcıların bir listesini içerir errno, math_errhandling, setjmpve va_end.

Başka kısıtlamalar geçerli olabilir. Örneğin, POSIX standardı normal kodda görünmesi muhtemel birçok tanımlayıcı ayırır:

  • EBüyük harfle başlayan isimler rakam veya büyük harf izledi:
    • ek hata kodu adları için kullanılabilir.
  • Ya küçük harfle başlayan ya isda toküçük harfle başlayan isimler
    • ek karakter testi ve dönüştürme işlevleri için kullanılabilir.
  • İle başlayan isimler ve LC_ardından büyük harf
    • yerel özellikleri belirten ek makrolar için kullanılabilir.
  • Mevcut tüm matematik işlevlerinin adları son eklenmiş fveya layrılmış durumda
    • sırasıyla, şamandıra ve uzun ikili argümanlar üzerinde çalışan ilgili işlevler için.
  • İle başlayan ve SIGbüyük harfle başlayan isimler saklıdır
    • ek sinyal adları için.
  • İle başlayan ve SIG_büyük harfle başlayan isimler saklıdır
    • ek sinyal eylemleri için.
  • İle başlayan isimler str, memya wcsbir küçük harflerden oluşan saklıdır
    • ek dize ve dizi işlevleri için.
  • Herhangi bir küçük harfle başlayan PRIveya SCNonu izleyen veya Xayrılmış harfler
    • ek biçim belirleyici makrolar için
  • İle biten isimler _tsaklıdır
    • ek tür adları için.

Bu adları kendi amaçlarınız için kullanmak, bir soruna neden olmayabilirken, bu standardın gelecekteki sürümleriyle çakışma olasılığını arttırır.


Şahsen sadece alt çizgi ile tanımlayıcıları başlatmıyorum. Kuralım için yeni bir ek: Hiçbir yerde çift alt çizgi kullanmayın, nadiren alt çizgi kullandığım için kolaydır.

Bu makalede araştırma yaptıktan sonra _t , POSIX standardına göre ayrıldığı için tanımlayıcılarımı artık bitirmiyorum.

Herhangi bir tanımlayıcı ile ilgili kural _tbeni çok şaşırttı. Bunun açıklayıcı ve resmi bölüm ve ayet arayan bir POSIX standardı (henüz emin değilim) olduğunu düşünüyorum. Bu, ayrılmış adları listeleyen GNU libtool kılavuzundan alınmıştır .

CesarB, POSIX 2004 ayrılmış sembollerine ve 'diğer birçok ayrılmış önek ve son ekin ... orada bulunabileceğine' ilişkin aşağıdaki bağlantıyı sağlamıştır . POSIX 2008 saklıdır semboller burada tanımlanır. Kısıtlamalar, yukarıdaki kısıtlamalardan biraz daha nüanslıdır.


14
C ++ standardı C'yi içe aktarmaz, değil mi? Bildiğim kadarıyla belirli başlıkları içeriyorlar, ancak bir bütün olarak dili veya adlandırma kurallarını içe aktarmıyorlar. Ama evet, beni de şaşırttı. Ancak C olduğu için sadece global ns için geçerli olabilir. Ben okurken _t sınıflar içinde _t kullanmak için güvenli olmalı
jalf

27
C ++ Standardı, C Standardını "içe aktarmaz". Bu başvuruda C Standardı. C ++ kütüphane tanıtımı "Kütüphane aynı zamanda Standart C Kütüphanesinin olanaklarını da sağlar" diyor. Bunu, C Standard kütüphanesinin üstbilgilerini uygun değişikliklerle ekleyerek yapar, ancak "içe aktararak" yapmaz. C ++ Standardı, ayrılmış adları açıklayan kendi kurallarına sahiptir. C'de ayrılmış bir adın C ++ ile ayrılması gerekiyorsa, bunu söyleyeceğiniz yer budur. Ancak C ++ Standardı bunu söylemez. Bu yüzden C ayrılmış şeyler C ++ saklıdır olduğunu sanmıyorum - ama ben de yanlış olabilir.
Johannes Schaub - litb

8
"_T" sorunu hakkında bulduğum budur: n1256 (C99 TC3) diyor ki: "int veya uint ile başlayan ve _t ile biten Typedef isimleri" saklıdır. Hala "foo_t" gibi isimlerin kullanılmasına izin veriyor düşünüyorum - ama ben bu daha sonra POSIX tarafından saklıdır düşünüyorum.
Johannes Schaub - litb

59
Yani 'tolerans' POSIX tarafından 'to' + küçük harfle mi başlar? Bahse girerim bir sürü kod bu kuralı kırar!
Sjoerd

23
@LokiAstari, " C ++ standardı C standardı olarak tanımlanmıştır. Temel olarak C ++ 'nın bu farklılıklar ve eklemelerle C olduğunu söyler. " Saçmalık! C ++ yalnızca [basic.fundamental] ve kitaplıktaki C standardını belirtir. Söylediğiniz doğruysa, C ++ bunu söylüyor _Boolve _ImaginaryC ++ 'da yok mu? C ++ dili açıkça "C" düzenlemeleri "ile değil, aksi halde standart çok daha kısa olabilir.
Jonathan Wakely

198

İsimlerin çarpışmasını önlemek için kurallar hem C ++ standardındadır (Stroustrup kitabına bakın) ve C ++ gurus (Sutter, vb.) Tarafından belirtilmiştir.

Kişisel kural

Vakalarla uğraşmak istemediğim ve basit bir kural istediğim için , hem basit hem de doğru olan kişisel bir kural tasarladım :

Bir sembolü adlandırırken, aşağıdaki durumlarda derleyici / OS / standart kütüphaneleri ile çarpışmayı önleyeceksiniz:

  • asla alt çizgi içeren bir sembol başlatma
  • Asla içinde iki ardışık alt çizgi bulunan bir sembole isim vermeyin.

Elbette, kodunuzu benzersiz bir ad alanına koymak da çarpışmayı önlemeye yardımcı olur (ancak kötü makrolara karşı koruma sağlamaz)

Bazı örnekler

(C / C ++ sembollerinin daha fazla kod kirletici olduğu için makroları kullanıyorum, ancak değişken adından sınıf adına herhangi bir şey olabilir)

#define _WRONG
#define __WRONG_AGAIN
#define RIGHT_
#define WRONG__WRONG
#define RIGHT_RIGHT
#define RIGHT_x_RIGHT

C ++ 0x taslağından alıntılar

Gönderen n3242.pdf dosyası (ben benzer olması son standart metin bekliyoruz):

17.6.3.3.2 Genel adlar [global.names]

Belirli adlar ve işlev imzaları her zaman uygulamaya ayrılmıştır:

- Bir çift alt çizgi _ _ içeren veya bir alt çizgi ve ardından bir büyük harf (2.12) ile başlayan her ad, herhangi bir kullanım için uygulamaya ayrılmıştır.

- Alt çizgiyle başlayan her ad, genel ad alanında ad olarak kullanılmak üzere uygulamaya ayrılmıştır.

Ayrıca:

17.6.3.3.5 Kullanıcı tanımlı değişmez ekler [usrlit.suffix]

Alt çizgi ile başlamayan değişmez sonek tanımlayıcıları gelecekteki standardizasyon için ayrılmıştır.

Eğer bir isim bir alt çizgi ile başlayan ve eğer Ok olacak bir küçük harflerden oluşan düşünün sürece bu son fıkrası, kafa karıştırıcı değil küresel ad alanında tanımlanan ...


9
@Meysam: __WRONG_AGAIN__arka arkaya iki alt çizgi içerir (iki başlangıç ​​ve iki bitiş), bu yüzden bu standarda göre yanlıştır.
paercebal

8
@ BЈовић: WRONG__WRONGarka arkaya iki alt çizgi (ikisi ortada) içerir, bu nedenle bu standarda göre yanlıştır
paercebal

2
kodunuzu benzersiz bir ad alanına yerleştirmek de çarpışmayı önlemeye yardımcı olur : ancak tanımlayıcı kapsamdan bağımsız olarak bir anahtar kelimeyle (ör __attribute__. GCC için) çarpışabileceğinden bu hala yeterli değildir .
Ruslan

1
Neden standarda göre ortada iki ardışık alt çizgi bulunması sorunu var ? Kullanıcı tanımlı değişmez ekler 1234567Lveya gibi değişmez değerler için geçerlidir 4.0f. IIRC, ohttp: //en.cppreference.com/w/cpp/language/user_literal anlamına gelir
Jason S

2
Why is there any problem of having two consecutive underscores in the middle according to the standard?Çünkü standartlar bunun saklı olduğunu söylüyor. Bu iyi ya da kötü stil hakkında bir tavsiye değil . Standarttan bir karar . Neden buna karar verdiler? Sanırım ilk derleyiciler standardizasyondan önce bu tür kuralları gayri resmi olarak kullandılar.
paercebal

38

Gönderen MSDN :

Bir tanımlayıcının başlangıcında iki ardışık alt çizgi karakterinin (__) veya tek bir büyük alt çizginin ardından büyük harf kullanılması, tüm kapsamlarda C ++ uygulamaları için ayrılmıştır. Geçerli veya gelecekteki ayrılmış tanımlayıcılarla olası çakışmalar nedeniyle, dosya kapsamındaki adlar için önce bir alt çizgi ve ardından küçük bir harf kullanmaktan kaçınmalısınız.

Bu, üye değişkeni öneki olarak tek bir alt çizgi kullanabileceğiniz anlamına gelir, bunu küçük harf izler.

Bu görünüşte C ++ standardının 17.4.3.1.2 bölümünden alınmıştır, ancak tam standart için orijinal bir kaynak bulamıyorum.

Ayrıca bu soruya bakın .


2
Benzer bir metni n3092.pdf dosyasında (C ++ 0x standardının taslağı) buldum: "17.6.3.3.2 Global isimler"
paercebal

7
İlginç bir şekilde, bu soruya doğrudan ve özlü bir cevap veren tek cevap gibi görünüyor.
hyde

9
@hyde: Aslında değil, çünkü global ad alanında önde gelen alt çizgileri olan hiçbir tanımlayıcıya sahip olmama kuralını atlıyor. Roger'ın cevabına bakın . MS VC belgelerinin C ++ standardında bir otorite olarak alıntılanmasına çok dikkat ediyorum.
sbi

@sbi Bu soruda, soru metnindeki soruyu boğulmadan doğrudan ve kısaca cevaplayan "tek bir alt çizgiyi üye değişkeni öneki olarak kullanabilirsiniz, ardından küçük harf kullanırsanız" ifadesini kullanıyordum metin duvarında.
hyde

5
Birincisi, hala aynı kuralın global ad alanı için bir başarısızlık olmadığına dair herhangi bir ipucunun olmadığını düşünüyorum. Daha da kötüsü, bitişik alt çizgilerin sadece bir tanımlayıcının başında değil, aynı zamanda herhangi bir tanımlayıcının da yasaklanmasıdır . Yani bu cevap sadece bir gerçeği atlamakla kalmıyor, aynı zamanda en azından bir tane aktif olarak yanlış iddiada bulunuyor. Dediğim gibi, MSVC belgelerine atıfta bulunmak, soru sadece VC ile ilgili olmadığı sürece yapamayacağım bir şeydir.
sbi

25

Sorunun diğer kısmına gelince, içsel bir şeyle çatışmamak için alt çizgiyi değişken adının sonuna koymak yaygındır .

Bunu sınıflar ve ad alanları içinde bile yapıyorum çünkü o zaman sadece bir kuralı hatırlamak zorundayım ("global kapsamdaki adın sonunda ve başka bir yerde adın başlangıcında" ile karşılaştırıldığında).


2

Evet, alt çizgiler bir tanımlayıcının herhangi bir yerinde kullanılabilir. Kuralların olduğuna inanıyorum: ilk karakterdeki az, AZ, _ ve sonraki karakterler için + 0-9.

Alt çizgi önekleri C kodunda yaygındır - tek bir alt çizgi "özel" anlamına gelir ve çift alt çizgi genellikle derleyici tarafından kullanılmak üzere ayrılır.


3
Kütüphanelerde yaygındır. Kullanıcı kodunda yaygın olmamalıdır.
Martin York

43
İnsanlar do C yazma kütüphaneleri, bilirsin.
John Millikin

7
"Evet, alt çizgiler bir tanımlayıcının herhangi bir yerinde kullanılabilir." Global tanımlayıcılar için bu yanlıştır. Roger'ın cevabına bakın .
sbi
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.