Apa aturan tentang menggunakan garis bawah dalam pengenal C ++?

Oct 23 2008

Biasanya di C ++ untuk menamai variabel anggota dengan semacam awalan untuk menunjukkan fakta bahwa mereka adalah variabel anggota, bukan variabel atau parameter lokal. Jika Anda berasal dari latar belakang MFC, Anda mungkin akan menggunakan m_foo. Saya juga pernah melihat myFoosesekali.

C # (atau mungkin hanya .NET) tampaknya merekomendasikan hanya menggunakan garis bawah, seperti pada _foo. Apakah ini diizinkan oleh standar C ++?

Jawaban

868 24revs,13users35%RogerPate Oct 23 2008 at 14:08

Aturan (yang tidak berubah di C ++ 11):

  • Dicadangkan dalam cakupan apa pun, termasuk untuk digunakan sebagai makro implementasi :
    • pengenal yang dimulai dengan garis bawah diikuti segera dengan huruf besar
    • pengenal yang berisi garis bawah yang berdekatan (atau "garis bawah ganda")
  • Dicadangkan di namespace global:
    • pengenal dimulai dengan garis bawah
  • Selain itu, semua yang ada di stdnamespace dicadangkan. (Anda diizinkan untuk menambahkan spesialisasi template.)

Dari Standar C ++ 2003:

17.4.3.1.2 Nama global [lib.global.names]

Kumpulan nama dan tanda tangan fungsi tertentu selalu dicadangkan untuk implementasi:

  • Setiap nama yang berisi garis bawah ganda ( __) atau dimulai dengan garis bawah diikuti dengan huruf besar (2.11) dicadangkan untuk implementasi untuk penggunaan apa pun.
  • Setiap nama yang dimulai dengan garis bawah dicadangkan untuk implementasi untuk digunakan sebagai nama di namespace global. 165

165) Nama-nama tersebut juga disediakan dalam namespace ::std(17.4.3.1).

Karena C ++ didasarkan pada standar C (1.1 / 2, C ++ 03) dan C99 adalah referensi normatif (1.2 / 1, C ++ 03), ini juga berlaku, dari Standar C 1999:

7.1.3 Pengenal yang dilindungi undang-undang

Setiap header mendeklarasikan atau mendefinisikan semua pengenal yang terdaftar dalam sub-klausa terkaitnya, dan secara opsional mendeklarasikan atau mendefinisikan pengidentifikasi yang terdaftar dalam sub-klausa dan pengidentifikasi arah perpustakaan di masa mendatang yang selalu dicadangkan baik untuk penggunaan apa pun atau untuk digunakan sebagai pengidentifikasi cakupan file.

  • Semua pengenal yang dimulai dengan garis bawah dan huruf besar atau garis bawah lainnya selalu disediakan untuk penggunaan apa pun.
  • Semua pengenal yang dimulai dengan garis bawah selalu disediakan untuk digunakan sebagai pengenal dengan cakupan file di ruang nama biasa dan tag.
  • Setiap nama makro di salah satu subklausul berikut (termasuk arah perpustakaan di masa mendatang) dicadangkan untuk digunakan sebagaimana ditentukan jika salah satu header terkaitnya disertakan; kecuali secara eksplisit dinyatakan lain (lihat 7.1.4).
  • Semua pengenal dengan tautan eksternal di salah satu subklausul berikut (termasuk petunjuk perpustakaan di masa mendatang) selalu dicadangkan untuk digunakan sebagai pengenal dengan tautan eksternal. 154
  • Setiap pengenal dengan cakupan file yang tercantum di salah satu subklausul berikut (termasuk arah perpustakaan di masa mendatang) dicadangkan untuk digunakan sebagai nama makro dan sebagai pengidentifikasi dengan cakupan file dalam ruang nama yang sama jika salah satu header terkaitnya disertakan.

Tidak ada pengenal lain yang dicadangkan. Jika program mendeklarasikan atau mendefinisikan pengenal dalam konteks yang dicadangkan (selain yang diizinkan oleh 7.1.4), atau mendefinisikan pengenal yang dicadangkan sebagai nama makro, perilaku tidak ditentukan.

Jika program menghapus (dengan #undef) definisi makro apa pun dari pengenal di grup pertama yang tercantum di atas, perilaku tidak ditentukan.

154) Daftar pengidentifikasi milik dengan linkage eksternal meliputi errno, math_errhandling, setjmp, dan va_end.

Pembatasan lain mungkin berlaku. Misalnya, standar POSIX menyimpan banyak pengenal yang mungkin muncul dalam kode normal:

  • Nama yang diawali dengan huruf kapital Ediikuti dengan angka atau huruf besar:
    • dapat digunakan untuk nama kode kesalahan tambahan.
  • Nama yang dimulai dengan salah satu isatau todiikuti dengan huruf kecil
    • dapat digunakan untuk pengujian karakter tambahan dan fungsi konversi.
  • Nama yang dimulai dengan LC_diikuti dengan huruf besar
    • dapat digunakan untuk makro tambahan yang menentukan atribut lokal.
  • Nama dari semua fungsi matematika yang ada dengan akhiran fatau ldicadangkan
    • untuk fungsi terkait yang masing-masing beroperasi pada argumen ganda mengambang dan panjang.
  • Nama yang dimulai dengan SIGdiikuti dengan huruf besar dicadangkan
    • untuk nama sinyal tambahan.
  • Nama yang dimulai dengan SIG_diikuti dengan huruf besar dicadangkan
    • untuk tindakan sinyal tambahan.
  • Nama yang dimulai dengan str, mematau wcsdiikuti dengan huruf kecil sudah dipesan
    • untuk fungsi string dan array tambahan.
  • Nama yang dimulai dengan PRIatau SCNdiikuti dengan huruf kecil atau Xsudah dipesan
    • untuk makro penentu format tambahan
  • Nama yang diakhiri dengan _tsudah dipesan
    • untuk nama tipe tambahan.

Meskipun menggunakan nama-nama ini untuk tujuan Anda sendiri saat ini mungkin tidak menimbulkan masalah, mereka meningkatkan kemungkinan konflik dengan versi standar yang akan datang.


Secara pribadi saya tidak memulai pengidentifikasi dengan garis bawah. Tambahan baru pada aturan saya: Jangan gunakan garis bawah ganda di mana pun, karena saya jarang menggunakan garis bawah.

Setelah melakukan penelitian pada artikel ini, saya tidak lagi mengakhiri pengidentifikasi saya _tkarena ini dicadangkan oleh standar POSIX.

Aturan tentang pengenal apa pun yang diakhiri dengan sangat _tmengejutkan saya. Saya pikir itu adalah standar POSIX (belum pasti) mencari klarifikasi dan pasal dan ayat resmi. Ini dari manual libtool GNU , mencantumkan nama yang dicadangkan.

CesarB menyediakan tautan berikut ke simbol dan catatan POSIX 2004 yang dicadangkan 'bahwa banyak prefiks dan sufiks yang dicadangkan lainnya ... dapat ditemukan di sana'. The POSIX 2008 simbol dilindungi didefinisikan di sini. Pembatasan tersebut agak lebih bernuansa daripada yang di atas.

202 paercebal Oct 23 2008 at 14:27

Aturan untuk menghindari benturan nama ada dalam standar C ++ (lihat buku Stroustrup) dan disebutkan oleh guru C ++ (Sutter, dll.).

Aturan pribadi

Karena saya tidak ingin menangani kasus, dan menginginkan aturan sederhana, saya telah merancang aturan pribadi yang sederhana dan benar:

Saat menamai simbol, Anda akan menghindari tabrakan dengan pustaka compiler / OS / standar jika Anda:

  • jangan pernah memulai simbol dengan garis bawah
  • jangan pernah memberi nama simbol dengan dua garis bawah yang berurutan di dalamnya.

Tentu saja, meletakkan kode Anda di namespace unik membantu menghindari tabrakan juga (tetapi tidak akan melindungi dari makro jahat)

Beberapa contoh

(Saya menggunakan makro karena mereka lebih banyak mencemari kode dari simbol C / C ++, tetapi bisa jadi apa saja mulai dari nama variabel hingga nama kelas)

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

Ekstrak dari draf C ++ 0x

Dari file n3242.pdf (Saya berharap teks standar akhir serupa):

17.6.3.3.2 Nama global [global.names]

Kumpulan nama dan tanda tangan fungsi tertentu selalu dicadangkan untuk implementasi:

- Setiap nama yang berisi garis bawah ganda _ _ atau dimulai dengan garis bawah diikuti dengan huruf besar (2.12) dicadangkan untuk implementasi untuk penggunaan apa pun.

- Setiap nama yang dimulai dengan garis bawah dicadangkan untuk implementasi untuk digunakan sebagai nama di namespace global.

Tetapi juga:

17.6.3.3.5 Sufiks literal yang ditentukan pengguna [usrlit.suffix]

Pengenal sufiks literal yang tidak dimulai dengan garis bawah disediakan untuk standardisasi di masa mendatang.

Klausa terakhir ini membingungkan, kecuali Anda menganggap bahwa nama yang dimulai dengan satu garis bawah dan diikuti dengan huruf kecil akan OK jika tidak ditentukan dalam namespace global ...

40 RogerLipscombe Oct 23 2008 at 14:06

Dari MSDN :

Penggunaan dua karakter garis bawah berurutan (__) di awal pengenal, atau satu garis bawah di awal diikuti dengan huruf kapital, dicadangkan untuk implementasi C ++ di semua cakupan. Anda harus menghindari penggunaan satu garis bawah yang diikuti dengan huruf kecil untuk nama dengan cakupan file karena kemungkinan konflik dengan pengenal yang dicadangkan saat ini atau di masa mendatang.

Ini berarti Anda dapat menggunakan satu garis bawah sebagai awalan variabel anggota, asalkan diikuti dengan huruf kecil.

Ini tampaknya diambil dari bagian 17.4.3.1.2 dari standar C ++, tetapi saya tidak dapat menemukan sumber asli untuk standar lengkap online.

Lihat juga pertanyaan ini .

25 MaxLybbert Nov 15 2008 at 03:03

Sedangkan untuk bagian lain dari pertanyaan, adalah umum untuk meletakkan garis bawah di akhir nama variabel agar tidak bentrok dengan internal apa pun.

Saya melakukan ini bahkan di dalam kelas dan ruang nama karena saya hanya perlu mengingat satu aturan (dibandingkan dengan "di akhir nama dalam cakupan global, dan awal nama di tempat lain").

1 JohnMillikin Oct 23 2008 at 14:05

Ya, garis bawah dapat digunakan di mana saja di pengenal. Saya yakin aturannya adalah: salah satu dari az, AZ, _ di karakter pertama dan + 0-9 untuk karakter berikut.

Awalan garis bawah umum digunakan dalam kode C - satu garis bawah berarti "pribadi", dan garis bawah ganda biasanya disediakan untuk digunakan oleh kompiler.