Question

Underscores in C++ Identifiers: Rules, Reserved Names, and Safe Naming

cpplanguage-lawyernaming-conventionsc++-faq

Question

In C++, it is common to use a naming convention for member variables so they are easy to distinguish from local variables or function parameters. For example, developers coming from MFC often use names like m_foo, while others use styles such as myFoo.

In C# and some .NET codebases, a common convention is to prefix member variables with a single underscore, such as _foo.

Is a name like _foo allowed by the C++ standard? More generally, what are the rules for using underscores in C++ identifiers?

Short Answer

By the end of this page, you will understand which C++ identifiers are valid, which underscore-based names are reserved by the language or standard library, and which naming styles are safe for your own code. You will also see practical examples of good and bad identifier choices for variables, functions, classes, and member variables.

Concept

In C++, identifiers are names you give to things such as variables, functions, classes, namespaces, and macros. The language allows underscores in identifiers, but there are important reservation rules.

The key idea is this:

  • Some names containing underscores are perfectly fine in your code.
  • Some names are reserved for the implementation, meaning the compiler, standard library, and platform headers may use them.
  • If you use a reserved name yourself, your program may still compile, but the behavior is not guaranteed to be safe or portable.

The important underscore rules

In general C++ code:

  • _foo is usually allowed for a member variable or local variable.
  • m_foo is also allowed.
  • my_foo is allowed.
  • __foo is reserved.
  • _Foo is reserved.
  • Any identifier containing __ anywhere is reserved.

A practical beginner-friendly summary:

  1. A single leading underscore followed by a lowercase letter is typically safe in normal code, such as _count.
  2. A leading underscore followed by an uppercase letter is reserved, such as _Count.
  3. Two leading underscores are reserved, such as __count.
  4. Two consecutive underscores anywhere are reserved, such as my__count.
  5. At global scope, many names beginning with _ should be avoided because they may conflict with implementation names.

Why this matters

Naming rules matter because:

  • They help you avoid collisions with compiler or library internals.
  • They improve portability across compilers and platforms.
  • They make code easier for teams to read and maintain.
  • They prevent subtle bugs caused by macro or implementation-name conflicts.

So yes, _foo can be allowed in C++, but context matters. It is much safer as a class member name than as a global name.

Mental Model

Think of identifier names like parking spaces in a shared building.

  • Most spaces are for you and your team.
  • Some spaces are reserved for building staff only.
  • If you park in a reserved staff space, your car may not be towed immediately, but you are still breaking the rules.

In C++, underscores are like labels that can accidentally put your name into a reserved area:

  • _foo is often like a normal space near the entrance: usually okay in the right area.
  • _Foo and __foo are like staff-only spaces: do not use them.
  • my__foo is also staff-only because the double underscore is reserved.

So the lesson is not just "can I write this name?" but also "is this name safely mine to use?"

Take Quiz

Syntax and Examples

Basic examples

int count = 0;      // OK
int my_count = 1;   // OK
int _count = 2;     // Usually OK in local or class scope
int m_count = 3;    // OK

These are commonly acceptable names in user code.

Names you should avoid

int __count = 0;    // Reserved
int _Count = 1;     // Reserved
int my__count = 2;  // Reserved

These names may conflict with compiler or library internals.

Member variable example

class User {
private:
    std::string _name;   // Commonly used, generally safe here
    int m_age;           // Also common and safe

public:
    User(std::string name, int age)
        : _name(name), m_age(age) {}
};

In this class, _name and m_age are both reasonable naming conventions.

Safer and clearer alternatives

class User {
private:
    std::string name_;
    int age_;
};

Many modern C++ codebases prefer a trailing underscore for member variables because it avoids reserved-name issues and clearly marks members.

Example of a bad global name

int _globalCounter = 0; // Best avoided

A leading underscore at global scope can conflict with implementation-reserved names, so this style is not recommended.

Step by Step Execution

Consider this example:

#include <iostream>

class Counter {
private:
    int _value;

public:
    Counter(int value) : _value(value) {}

    void increment() {
        _value++;
    }

    int value() const {
        return _value;
    }
};

int main() {
    Counter c(5);
    c.increment();
    std::cout << c.value() << '\n';
}

What happens step by step

  1. The class Counter is defined.
  2. It has a private member variable named _value.
  3. The constructor Counter(int value) receives a parameter named value.
  4. The initializer list : _value(value) stores the parameter into the member variable.
  5. In main(), Counter c(5); creates an object with _value set to 5.
  6. c.increment(); increases _value from 5 to 6.
  7. c.value() returns 6.
  8. The program prints 6.

Why this naming works

  • _value is a member variable inside a class.
  • It starts with a single underscore followed by a lowercase letter.
  • It does not use a double underscore.
  • It does not start with underscore + uppercase letter.

That makes it a commonly accepted style in C++, though many teams still prefer value_ for extra safety and consistency.

Real World Use Cases

Underscore naming rules appear in many real C++ situations:

Class member naming

Developers often use underscores to distinguish members from parameters:

class Config {
private:
    std::string file_path_;

public:
    Config(std::string file_path) : file_path_(file_path) {}
};

Avoiding naming collisions in APIs

When building libraries, safe names help avoid conflicts with platform headers, compiler internals, or macros.

Cross-platform code

A name that works on one compiler may conflict on another if it uses reserved identifier patterns. Following the rules improves portability.

Large teams and style guides

Teams often choose one of these conventions:

  • m_name
  • _name
  • name_
  • memberName

From a language-rules perspective, name_ is often the safest underscore-based style.

Generated code and tooling

Some code generators or frameworks produce identifiers automatically. Knowing reserved-name rules helps prevent invalid or risky generated names.

Take Quiz

Real Codebase Usage

In real projects, developers usually care less about whether a name merely compiles and more about whether it is safe, readable, and consistent.

Common team conventions

Trailing underscore for members

class Session {
private:
    std::string token_;
    int timeout_seconds_;
};

Why teams like it:

  • Avoids leading-underscore reserved-name pitfalls
  • Clearly marks member variables
  • Works well with constructor parameters
Session(std::string token, int timeout_seconds)
    : token_(token), timeout_seconds_(timeout_seconds) {}

m_ prefix

class Session {
private:
    std::string m_token;
};

This is older but still widely used, especially in legacy codebases.

Guarding against naming conflicts

In headers and public APIs, developers avoid risky names such as:

  • _Size
  • __buffer
  • value__internal

These can collide with implementation details or violate the standard.

Error handling and maintenance

A safe naming convention reduces confusion during refactoring. For example, when a local variable and a member variable share the same logical meaning, a clear convention avoids mistakes:

void set_name(const std::string& name) {
    name_ = name;
}

This is cleaner than inventing awkward parameter names just to avoid collisions.

Common Mistakes

1. Using reserved names because they compile

Just because a compiler accepts a name does not mean it is safe.

int __value = 10; // Compiles on some systems, but reserved

Avoid any name with __.

2. Using underscore + uppercase letter

class Example {
    int _Value; // Reserved
};

Use _value or value_ instead.

3. Using leading underscores at global scope

int _counter = 0; // Best avoided at global scope

Prefer:

int global_counter = 0;

4. Creating double underscores accidentally

int user__id = 5; // Reserved because of double underscore

Prefer:

int user_id = 5;

5. Mixing too many naming styles

class Person {
    std::string _name;
    int m_age;
    std::string address_;
};

This is legal, but inconsistent. Pick one style for the codebase.

6. Confusing language rules with style rules

The C++ standard defines what is reserved. Your team style guide defines what is preferred. These are not the same thing.

  • _name may be allowed
  • name_ may be preferred
  • __name is reserved and should not be used

Comparisons

Naming styleExampleUsually legal in user code?Recommended?Notes
Plain namecountYesYesSimple and safe
Internal underscoreuser_idYesYesVery common
Leading underscore + lowercase_countOften yesSometimesUsually okay in class/local scope
Leading underscore + uppercase_CountNo, reservedNoAvoid completely
Double leading underscore__countNo, reservedNoAvoid completely
Double underscore anywheremy__countNo, reservedNoAvoid completely
m_ prefixm_countYesSometimesCommon in older codebases
Trailing underscorecount_YesYesPopular modern C++ style

_name vs name_

StyleProsCons
_nameShort, familiar to developers from C# or some C++ codebasesCan be risky at global scope; easier to violate reserved-name rules accidentally
name_Safe with respect to reserved leading underscore rules; clear for membersLess common outside C++
m_nameExplicit member prefix; common in older codebasesMore verbose

If you are choosing a new convention for modern C++, name_ is often the safest option.

Take Quiz

Cheat Sheet

Safe identifier rules in C++

  • Letters, digits, and underscores can appear in identifiers.
  • Identifiers cannot start with a digit.
  • A single underscore is not automatically illegal.

Avoid these reserved patterns

__name      // reserved
_Name       // reserved
my__name    // reserved

Usually safe patterns

name
user_id
_value      // usually okay in class/local scope
value_
m_value

Best practice

  • Prefer name_ for member variables if you want to avoid reserved-name issues.
  • Avoid leading underscores in global names.
  • Never use double underscores.
  • Never use underscore followed by uppercase.
  • Be consistent across the codebase.

Quick recommendation

For new C++ code:

class Example {
private:
    int value_;
};

FAQ

Is _foo legal in C++?

Usually yes, especially for a local variable or class member, as long as it does not fall into a reserved pattern.

Is _Foo legal in C++?

No. An identifier beginning with an underscore followed by an uppercase letter is reserved for the implementation.

Are double underscores allowed in C++ names?

You should not use them in your own identifiers. Names with __ are reserved.

Is m_foo allowed in C++?

Yes. m_foo is a common and safe naming convention in user code.

Why do many C++ style guides prefer foo_ over _foo?

Because foo_ avoids the special reserved-name rules around leading underscores and is safer across scopes.

Can I use a leading underscore for global variables?

It is best not to. Leading underscores at global scope can conflict with implementation-reserved names.

Does the compiler always reject reserved identifiers?

No. Some reserved names may compile without errors, but they are still not safe or portable to use.

What is the safest underscore style for member variables?

A trailing underscore, such as value_, is widely considered one of the safest and clearest choices in modern C++.

Take Quiz

Mini Project

Description

Create a small C++ program that demonstrates safe and unsafe naming conventions for identifiers. The goal is to practice recognizing which underscore-based names are good choices for your own code and which ones should be avoided because they are reserved.

Goal

Write a program with a class that uses a safe member naming convention and prints stored values clearly.

Requirements

  1. Create a class with at least two private member variables.
  2. Use a safe naming convention for the member variables.
  3. Add a constructor that initializes those members.
  4. Add getter or print functions to access the stored values.
  5. Include comments showing examples of reserved names that should not be used.
Take Quiz

Keep learning

Related questions

View more