C ++識別子でアンダースコアを使用する場合のルールは何ですか?


930

C ++では、メンバー変数にローカル変数やパラメーターではなく、メンバー変数であることを示すために、何らかの接頭辞を付けてメンバー変数に名前を付けるのが一般的です。MFCのバックグラウンドを持っている場合は、おそらくを使用しますm_foomyFooたまに見たこともあります。

C#(またはおそらく.NET)は、のように、アンダースコアのみの使用を推奨しているよう_fooです。これはC ++標準で許可されていますか?


3
そのことについてはglibcのマニュアルページはで見つけることができますgnu.org/software/libc/manual/html_node/Reserved-Names.html編集:も参照opengroup.org/onlinepubs/009695399/functions/xsh_chap02_02.html
CesarB

6
これらのルールを知らないことは、コードがコンパイルまたは実行されないことを必ずしも意味しないことに注意してください。衝突。これを裏付けるために、命名規則として_大文字をどこでも使用している重要なシステムの特定の実装を知っています。これによるエラーはありません。もちろんそれは悪い習慣です。
g24l 2015年

回答:


852

ルール(C ++ 11では変更されていません):

  • 実装マクロとしての使用を含む、すべてのスコープで予約済み:
    • アンダースコアで始まり、直後に大文字が続く識別子
    • 隣接するアンダースコアを含む識別子(または「ダブルアンダースコア」)
  • グローバル名前空間で予約済み:
    • 下線で始まる識別子
  • また、stdネームスペースのすべてが予約されています。(ただし、テンプレートの特殊化を追加することはできます。)

2003 C ++標準から:

17.4.3.1.2グローバル名[lib.global.names]

名前と関数シグネチャの特定のセットは、常に実装に予約されています。

  • 二重下線(__)を含むか、下線で始まり、その後に大文字(2.11)が続く名前は、実装用に予約されています。
  • アンダースコアで始まる各名前は、グローバル名前空間の名前として使用するために実装で予約されています。165

165)そのような名前は名前空間でも予約されています::std(17.4.3.1)。

C ++はC標準(1.1 / 2、C ++ 03)に基づいており、C99は規範的な参照(1.2 / 1、C ++ 03)であるため、1999 C標準から次のように適用されます。

7.1.3予約済み識別子

各ヘッダーは、関連する副次句にリストされているすべての識別子を宣言または定義し、オプションで、関連する将来のライブラリー指示副次句にリストされている識別子と、常に使用またはファイルスコープ識別子として使用するために予約されている識別子を宣言または定義します。

  • アンダースコアで始まり、大文字または別のアンダースコアで始まるすべての識別子は、常に使用のために予約されています。
  • アンダースコアで始まるすべての識別子は、通常の名前空間とタグ名前空間の両方でファイルスコープを持つ識別子として使用するために常に予約されています。
  • 以下の副節(将来のライブラリーの指示を含む)の各マクロ名は、関連するヘッダーが含まれている場合に、指定されたとおりに使用するために予約されています。特に明記されていない限り(7.1.4を参照)。
  • 以下の副節(将来のライブラリーの指示を含む)のいずれかに外部リンケージがあるすべての識別子は、外部リンケージがある識別子として使用するために常に予約されています。154
  • 次の副節(将来のライブラリの指示を含む)のいずれかにリストされたファイルスコープを持つ各識別子は、マクロ名として、および関連するヘッダーが含まれている場合は同じ名前空間内のファイルスコープを持つ識別子として使用するために予約されています。

他の識別子は予約されていません。プログラムが予約されているコンテキストで識別子を宣言または定義している場合(7.1.4で許可されている場合を除く)、または予約されている識別子をマクロ名として定義している場合の動作は未定義です。

プログラムが#undef上記の最初のグループの識別子のマクロ定義を(を使用して)削除した場合の動作は未定義です。

154)外部結合を持つ予約識別子のリストは、errnomath_errhandlingsetjmp、およびva_end

その他の制限が適用される場合があります。たとえば、POSIX標準では、通常のコードで表示される可能性が高い多くの識別子が予約されています。

  • E大文字で始まる名前は、数字または大文字の後に続きます。
    • 追加のエラーコード名に使用できます。
  • いずれかで始まる名前isまたはto小文字が続きます
    • 追加の文字テストおよび変換機能に使用できます。
  • LC_大文字 で始まる名前
    • ロケール属性を指定する追加のマクロに使用できます。
  • サフィックスが付いている、fまたはl予約されている すべての既存の数学関数の名前
    • floatおよびlong double引数をそれぞれ操作する対応する関数用。
  • SIG大文字で始まる名前は予約されています
    • 追加の信号名。
  • SIG_大文字で始まる名前は予約されています
    • 追加のシグナルアクション用。
  • 始まる名前strmemまたはwcs小文字が続くが予約されています
    • 追加の文字列および配列関数用。
  • 小文字で始まるPRIまたはSCN後に続く名前、またはX予約されている 名前
    • 追加のフォーマット指定子マクロ用
  • で終わる名前_tは予約されています
    • 追加のタイプ名。

現時点でこれらの名前を独自の目的で使用しても問題は発生しない可能性がありますが、その標準の将来のバージョンと競合する可能性があります。


個人的には、識別子をアンダースコアで始めないでください。ルールへの新たな追加:アンダースコアを2つ使用しないでください。これは、アンダースコアをほとんど使用しないため簡単です。

この記事を調査した後、識別子が_t POSIX標準で予約されているため、識別子で終わることはもうありません。

で終わる識別子に関する規則は、_t私をとても驚かせました。私はそれがPOSIX標準(まだ定かではありません)だと思います。これは、GNU libtoolマニュアルからのもので、予約済みの名前がリストされています。

CesarBは、POSIX 2004の予約済みシンボルおよびメモへの次のリンクを提供し、「他の多くの予約済みの接頭辞および接尾辞...がそこにある」と注記しています。ここでは、 POSIX 2008の予約済みシンボルが定義されています。制限は、上記のものよりも多少微妙です。


14
C ++標準はCの標準を「インポート」しませんか?それらは特定のヘッダーをインポートしますが、私の知る限り、言語全体や命名規則はインポートしません。しかし、そうです、_tの人も私を驚かせました。ただし、Cであるため、グローバルnsにのみ適用できます。私が読んでいるように、クラス内で_tを使用しても安全です
jalf

27
C ++標準はC標準を「インポート」しません。C規格を参照しています。C ++ライブラリの紹介では、「ライブラリにより、標準Cライブラリの機能も利用できるようになります」と記載されています。これは、適切な変更を加えたC標準ライブラリのヘッダーを含めることによって行われますが、「インポート」することでは行われません。C ++標準には、予約名を説明する独自のルールセットがあります。Cで予約された名前をC ++で予約する必要がある場合、それはこれを言う場所です。しかし、C ++標準ではそうは言われていません。だから私はCで予約されているものがC ++で予約されているとは信じていません-しかし私は間違っている可能性があります。
Johannes Schaub-litb

8
これは「_t」の問題について私が見つけたものです:n1256(C99 TC3)は言う:「intまたはuintで始まり、_tで終わるTypedef名」は予約されています。「foo_t」のような名前を使用することはまだ許可されていると思いますが、これらはPOSIXによって予約されていると思います。
Johannes Schaub-litb

59
したがって、「to」+小文字で始まるため、「許容度」はPOSIXによって予約されていますか?多くのコードがこのルールに違反しているに違いない!
シェールド

23
@LokiAstari、「C ++標準はC標準に基づいて定義されています。基本的に、C ++はこれらの相違点と追加点を含むCであると述べています。」C ++は、[basic.fundamental]のC標準とライブラリのみを参照します。あなたが言うことが本当なら、C ++はどこでそれ_Boolを言って_ImaginaryC ++に存在しないのですか?C ++言語は、Cへの「編集」に関してではなく、明示的に定義されています。そうでない場合、標準ははるかに短くなる可能性があります。
Jonathan Wakely 2013

198

名前の衝突を回避するための規則は、C ++標準(Stroustrupの本を参照)にあり、C ++の教祖(Sutterなど)によって言及されています。

個人ルール

私はケースを扱いたくなかったし、単純なルールが欲しかったので、私はシンプルで正しい両方の個人的なものを設計しました:

シンボルに名前を付ける場合、以下の場合、コンパイラ/ OS /標準ライブラリとの衝突を回避できます。

  • シンボルをアンダースコアで始めないでください
  • 内部に2つの連続したアンダースコアを含むシンボルに名前を付けないでください。

もちろん、コードを一意の名前空間に配置すると、衝突も回避できます(ただし、悪質なマクロからは保護されません)。

いくつかの例

(マクロはC / C ++シンボルのコードを汚染するため、マクロを使用しますが、変数名からクラス名まで何でもかまいません)

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

C ++ 0xドラフトからの抜粋

n3242.pdfファイルから(最終的な標準テキストは同様であることを期待しています):

17.6.3.3.2グローバル名[global.names]

名前と関数シグネチャの特定のセットは、常に実装に予約されています。

—二重アンダースコア_ _を含む、またはアンダースコアで始まり、その後に大文字(2.12)が続く名前は、実装用に予約されています。

—アンダースコアで始まる各名前は、グローバル名前空間の名前として使用するために実装に予約されています。

だけでなく:

17.6.3.3.5ユーザー定義のリテラルサフィックス[usrlit.suffix]

アンダースコアで始まらないリテラルサフィックス識別子は、将来の標準化のために予約されています。

この最後の句は、1つのアンダースコアで始まり、その後に小文字が続く名前がグローバル名前空間で定義されていない場合 Okであると考えない限り、混乱を招きます...


9
@Meysam:__WRONG_AGAIN__2つの連続したアンダースコア(最初に2つ、最後に2つ)が含まれているため、これは標準では間違っています。
paercebal 2012年

8
@BЈовић:WRONG__WRONG2つの連続したアンダースコア(中央に2つ)が含まれているため、これは標準的に間違っています
paercebal

2
コードを一意の名前空間に配置すると、衝突を回避するのにも役立ちます。ただし、識別子はスコープに関係なく(たとえば__attribute__、GCCの場合)キーワードと衝突する可能性があるため、これだけでは不十分です。
ルスラン

1
標準に従って 2つの連続したアンダースコアが中央にあるという問題があるのはなぜですか?ユーザー定義のリテラルサフィックスは、1234567Lまたはのようなリテラル値に適用されます4.0f。IIRCこれはohttp://en.cppreference.com/w/cpp/language/user_literalを参照
Jason S

2
Why is there any problem of having two consecutive underscores in the middle according to the standard?標準はそれらが予約されていると言うので。これはスタイルの良し悪しに関するアドバイスではありません。それは標準からの決定です。なぜ彼らはこれを決めたのですか?最初のコンパイラは、標準化の前にそのような規則を非公式に使用していたと思います。
paercebal 2017

38

MSDNから:

識別子の先頭に2つの連続するアンダースコア文字(__)を使用するか、先頭のアンダースコアの後に大文字を1つ使用することは、すべてのスコープのC ++実装用に予約されています。現在または将来の予約済み識別子と競合する可能性があるため、ファイルスコープの名前には、先頭のアンダースコアの後に小文字を続けて使用しないでください。

つまり、小文字が続く限り、単一のアンダースコアをメンバー変数の接頭辞として使用できます。

これは明らかにC ++標準のセクション17.4.3.1.2から取られていますが、完全な標準の元のソースをオンラインで見つけることができません。

この質問も参照してください。


2
n3092.pdf(C ++ 0x標準のドラフト)のセクション「17.6.3.3.2グローバル名」で同様のテキストを見つけました
paercebal

7
興味深いことに、これが質問に対する直接的な簡潔な回答を持つ唯一の回答のようです。
ハイド

9
@hyde:実際にはそうではありません。グローバル名前空間でアンダースコアが先行する識別子を持たないというルールをスキップしているためです。ロジャーの答えを参照してください。C ++標準の権威としてのMS VCドキュメントの引用には非常に注意します。
sbi

@sbi この回答では、「単一のアンダースコアを小文字の後に続けてメンバー変数のプレフィックスとして使用できます」と言及し ていました。テキストの壁に。
ハイド2015

5
まず、同じルールがグローバル名前空間に適用されないというヒントがないことはまだ失敗だと私は考えています。ただし、さらに悪いのは、隣接するアンダースコアが識別子の最初だけでなくどこでも禁止されていることです。したがって、この答えは事実を単に省略しているだけではなく、実際に少なくとも1つの積極的に間違った主張をしています。先ほど述べたように、MSVCドキュメントを参照することは、質問がVCのみに関するものでない限り、私が行うことはないでしょう。
sbi 2015

25

質問の他の部分に関しては、内部で何かと衝突しないように変数名の最後にアンダースコアを置くのが一般的です。

これを行うのは、クラスと名前空間の内部でも同じです(「グローバルスコープ内の名前の末尾と、他のすべての場所での名前の先頭」と比較して)1つのルールを覚えればよいだけです。


2

はい、アンダースコアは識別子のどこにでも使用できます。ルールは次のとおりです。最初の文字のaz、AZ、_、および後続の文字の+ 0-9。

下線の接頭辞はCコードでは一般的です。1つの下線は「プライベート」を意味し、2つの下線は通常、コンパイラーが使用するために予約されています。


3
ライブラリでは一般的です。これらは、ユーザーコードでは一般的ではありません。
マーティンヨーク、

43
人々 Cでライブラリを作成します。
ジョンミリキン

7
「はい、アンダースコアは識別子のどこでも使用できます。」これは、グローバル識別子では間違っています。ロジャーの答えを参照してください。
sbi
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.