In C, an underscore is the character _. It is part of the language’s identifier syntax, so programmers can use it in names for variables, functions, types, and other entities. It is not an operator, and the phrase “C underscore” has no separate, official meaning beyond the character’s role in C. The main practical points are that underscores can separate words in identifiers, while some underscore-prefixed names are reserved for the language implementation and should not be chosen for your own code.
What the Underscore Means in C
The underscore is a punctuation character that C permits in identifiers. An identifier is a name a program uses for something such as a variable or function. For example, total_cost and read_input are identifiers. The underscore helps distinguish the parts of a name without inserting a space, which is not allowed inside an ordinary C identifier.
The character is called an underscore because it is a short horizontal line positioned below the usual writing line. Its name predates C; C uses the existing character as one of the characters available in source code. The language does not assign it a special arithmetic or logical operation. In total_cost, it is simply part of the identifier’s spelling.
There is also no standard English or C vocabulary term called “C underscore” that defines a special programming feature. If someone says “underscore in C,” they usually mean the character’s place in a name, a name that begins with it, or a spelling such as _Bool. The surrounding code determines which meaning is relevant.
Where Underscores Are Allowed
For portable C code, an identifier may use letters, digits, and underscores. It must begin with a letter or underscore, not a digit. After the first character, digits are allowed. C identifiers are case-sensitive, so file_name, File_name, and file_Name are different names.
user_nameis a valid identifier: it begins with a letter and contains an underscore._user_nameis syntactically a valid identifier, though a leading underscore raises reservation and style concerns.user_name2is valid because the digit does not appear at the beginning.2user_nameis invalid as an identifier because it begins with a digit.user nameis not one identifier: the space separates two tokens.
These rules apply to names such as variables, functions, typedef names, and structure or union tags, subject to C’s other rules. A keyword cannot be used as an identifier, whether or not an underscore is added elsewhere. For instance, return_value is a possible identifier, but return itself is a keyword and cannot be reused as a name.
Why C Programmers Use Underscores
The most common everyday use is separating words in a longer identifier. This style is often called snake case: words are written in lowercase and divided by underscores. It can make names easier to scan, especially when a name describes a value or action in several words.
int item_count;
int find_user_record(void);
Here, item_count communicates that the value represents a count of items, while find_user_record reads as an action. The underscore does not change how C evaluates either name. It improves readability for people and helps keep multiword names distinct.
Underscores also appear in macro names, where uppercase words separated by underscores are a familiar convention, as in BUFFER_LIMIT. This is a convention rather than a requirement of the language. C does not require variables to use lowercase or macros to use uppercase; consistent naming within a project matters more than any single visual style.
Some programs use underscores to convey internal or generated status, or to follow an existing codebase’s naming rules. That does not make every underscore-prefixed name safe. The language’s reserved-name rules take precedence over a local naming convention.
Reserved Names and Leading Underscores
The most important caution is that C reserves certain identifiers for the implementation, including names used by compilers and standard-library facilities. A programmer who defines a reserved name may collide with a library declaration or interfere with implementation-specific code. Such a program may fail to compile, behave unexpectedly, or stop being portable.
- Names beginning with two underscores are reserved for any use.
- Names beginning with an underscore followed by an uppercase letter are reserved for any use.
- Names beginning with an underscore are reserved for use as identifiers at file scope in the ordinary and tag namespaces.
“File scope” generally means a declaration made outside a function body. The ordinary namespace includes names such as objects, functions, typedefs, and enumeration constants; the tag namespace includes structure, union, and enumeration tags. The reservation is not just advice about appearance: it is part of the rules intended to leave implementation names available.
For example, do not create a global variable named _cache, a function named __parse, or a type named _Record. The double-underscore and underscore-plus-uppercase patterns are reserved regardless of where they appear. A name beginning with an underscore followed by a lowercase letter is not reserved in every possible context by that specific rule, but using such names for your own code is still a poor portability habit. It can be confusing and may conflict with extensions or conventions used by a toolchain.
Prefer names that begin with a letter, such as cache, parse_record, or record_type. This avoids a needless standards question and makes ownership of the name clear. Also avoid assuming that a name is safe just because one compiler accepts it; acceptance does not mean the name is available for portable user code.
Underscores in C Keywords and Library Names
Some standard C spellings begin with an underscore. _Bool, for example, is a C keyword. It is not a user-created identifier following an informal naming pattern. The underscore is part of the exact spelling specified by the language. Other underscore-prefixed spellings are associated with language features or library declarations in particular C revisions.
This can seem to conflict with the warning about reserved names, but it does not. The implementation and the language standard may use reserved spellings; programmers leave those spellings alone. Do not imitate a standard-looking name for a private function or variable. If you need a Boolean variable, a name such as is_ready is a clearer choice than inventing a new underscore-prefixed type-like name.
Compiler extensions may introduce additional reserved names. Because extensions differ between implementations, a name that works in one environment may not be portable to another. When working with a particular compiler or library, follow its documentation, but keep application-defined names away from the reserved underscore patterns.
Practical Examples and Naming Choices
Consider a small program that tracks a user’s reading progress. A readable set of identifiers might be page_count, current_page, and update_progress. The underscores divide words while leaving the names within the ordinary identifier rules. A function call could look like this:
int current_page;
int page_count;
current_page = read_page();
page_count = count_pages();
The underscores here do not create a relationship between the variables, and they do not alter the program’s control flow. Each full spelling is an independent identifier. The programmer communicates meaning through the words selected and the way the code uses each name.
Compare that with _current_page at file scope. It may look like a way to mark a private or hidden variable, but the leading underscore makes the name reserved in that context. It is better to express the intended role with a safe spelling, such as internal_current_page, or by using C’s actual scope and linkage mechanisms where appropriate. A leading underscore does not itself make a variable private.
For macros, a conventional spelling might be DEFAULT_PAGE_COUNT. Avoid turning it into _DEFAULT_PAGE_COUNT or __DEFAULT_PAGE_COUNT; those forms enter reserved territory. Likewise, do not use a double underscore merely to make a name look unique. Descriptive names and appropriate scope are safer ways to reduce collisions.
Common Misunderstandings
- “An underscore makes a name private.” It does not. C visibility is governed by scope, linkage, and declarations, not by a leading underscore as a general rule.
- “Underscores are operators.” They are not operators in C. In an identifier, an underscore is part of the name; elsewhere, it is simply a character token where the language permits it.
- “Any name starting with an underscore is always invalid.” Not exactly. Some are valid syntactically, and the reservation rules depend on the pattern and context. The practical advice remains to avoid leading underscores in user-defined names.
- “A compiler accepting a name proves it is portable.” It does not. An implementation may accept a reserved spelling or use it for an extension, but another environment can treat it differently.
Another frequent mistake is confusing the underscore with a space. In source code, first_name is one identifier, while first name is separated into two tokens. If a name appears not to work, check for spaces, punctuation, misspellings, and case differences before assuming the underscore has a special effect.
Frequently Asked Questions
What does an underscore mean in C?
The underscore is a character that can appear in an identifier. It commonly separates words in names such as file_size. On its own, it does not mean “private,” perform an operation, or change a variable’s value.
Can a C variable name start with an underscore?
It can be syntactically valid, but the context matters because C reserves some underscore-prefixed names. In particular, names beginning with an underscore are reserved at file scope in the ordinary and tag namespaces. For portable user code, start names with a letter instead.
Are double underscores allowed in C identifiers?
They can appear in spellings recognized by the language or implementation, but identifiers beginning with two underscores are reserved for any use. Do not use them for application-defined names.
Is underscore a C operator?
No. It is not an arithmetic, comparison, or logical operator. It is normally encountered as part of an identifier, though the exact role of any character depends on its position in the source.
Why do C names use underscores instead of spaces?
Spaces separate tokens in C, so they cannot divide words inside one identifier. Underscores provide a visible separator while keeping the spelling a single name. They are a common style choice, not a requirement.