What are the rules about using an underscore in a C++ identifier?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Underscores are allowed in C++ identifiers, but some underscore patterns are reserved to the implementation. The practical rule is simple: internal underscores are fine, trailing underscores are usually safe, and leading underscores require care.
The Basic Syntax Rule
From a pure syntax point of view, underscores are valid characters in identifiers.
These are syntactically valid:
But syntactic validity is not the whole story. Some names are reserved for the compiler, standard library, or other implementation details, and using them in your own code can lead to undefined or non-portable behavior.
Reserved Underscore Patterns
The most important C++ rules are:
- any identifier containing a double underscore is reserved to the implementation
- any identifier beginning with an underscore followed by an uppercase letter is reserved to the implementation
- any identifier beginning with a single underscore is reserved in the global namespace
That means names such as these should be avoided in user code:
These rules are why many style guides avoid leading underscores entirely unless there is a very controlled local convention.
Safe And Common Naming Patterns
Internal underscores are the safest and most common style.
Trailing underscores are also common, especially for private data members.
This style avoids collisions with constructor parameters while staying away from reserved leading-underscore patterns.
Why Leading Underscores Cause Trouble
A name like _size may look harmless inside a function, and in some scopes it is not automatically reserved by the language. But it is still easy to create style inconsistencies or accidental collisions once that naming habit spreads to namespace scope, macros, or library-facing code.
That is why the conservative advice is stronger than the minimum legal rule:
- avoid double underscores everywhere
- avoid
_Uppercaseeverywhere - avoid leading underscores entirely unless you have a very specific reason and understand the scope rules
This is not just style pedantry. It is a portability and maintainability rule.
Examples Of Good And Bad Choices
A few examples make the distinction clearer.
Good:
Bad or risky:
If you want a naming convention for members, trailing underscore is usually the least problematic choice.
What About Macros?
Macros follow the same reservation concerns, and they are even more dangerous because they operate at preprocessing time.
Avoid macro names like:
A safer header guard style is something like:
or #pragma once if that fits your team's policy.
Style Versus Language Rules
It is worth separating two ideas:
- what the language grammar allows
- what the implementation reserves
Something can be accepted by the compiler and still be a bad idea because the name is reserved. That is why "it compiles" is not the right test here.
A good team convention should stay comfortably inside the non-reserved space.
Common Pitfalls
The most common mistake is thinking that any name accepted by the parser is automatically safe. Reserved identifiers can compile and still be wrong to use.
Another mistake is using _member as a blanket style rule without noticing that the same habit leaks into global or namespace scope.
Developers also forget the double-underscore rule. In C++, double underscores are not a decorative convention; they are implementation territory.
Finally, avoid inventing macro or header-guard names with leading underscores. Those conflicts are easy to miss and hard to debug later.
Summary
- Underscores are allowed in C++ identifiers, but some underscore patterns are reserved.
- Avoid any identifier containing a double underscore.
- Avoid names beginning with underscore plus uppercase letter.
- Avoid leading underscores in global namespace and, as a practical rule, usually avoid them entirely.
- Internal underscores and trailing underscores are the safest common naming patterns.

