Why does C have keywords starting with underscore

C developed and become very popular before it was planned by a standards committee. In consequence, there was a lot of existing code.

When setting a C standard, or updating an old standard, an important goal is not to “break” old code. It is desirable that code that worked with previous compilers continue to work with new versions of the C language.

Introducing a new keyword (or any new definition or meaning of a word) can break old code, since, when compiling, the word will have its new keyword meaning and not the identifier meaning it had with the previous compilers. The code will have to be edited. In addition to the expense of paying people to edit the code, this has a risk of introducing bugs if any mistakes are made.

To deal with this, a rule was made that identifiers starting with underscore were reserved. Making this rule did not break much old software, since most people writing software choose to use identifiers beginning with letters, not underscore. This rule gives the C standard a new ability: By using underscore when adding new keywords or other new meanings for words, it is able to do so without breaking old code, as long as that old code obeyed the rule.

New versions of the C standard sometimes introduce new meanings for words that do not begin with an underscore, such as bool. However, these new meanings are generally not introduced in the core language. Rather, they are introduced only in new headers. In making a bool type, the C standard provided a new header, <stdbool.h>. Since old code could not be including <stdbool.h> since it did not exist when the code was written, defining bool in <stdbool.h> would not break old code. At the same time, it gives programmers writing new code the ability to use the new bool feature by including <stdbool.h>.


Eric and Clifford has provided good answers, but I add a quote from the C11 standard to support it.

  • All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
  • All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.

https://port70.net/~nsz/c/c11/n1570.html#7.1.3

One might also consider this:

Typedef names beginning with int or uint and ending with _t may be added to the types defined in the stdint.h header. Macro names beginning with INT or UINT and ending with _MAX, _MIN, or _C may be added to the macros defined in the stdint.h header.

https://port70.net/~nsz/c/c11/n1570.html#7.31.10p1


In the standard, any name that begins with a double underscore or an underscore followed by an uppercase letter is reserved. This is useful because C lacks named namespaces. By reserving all such symbols, new and implementation specific keywords can be introduced to the language without clashing with symbols defined in existing code.

The macros such as bool and static_assert are "convenience macros", they allow you to use the reserved keyword symbols without the underscores and capitals at the small risk of a name clash. However they provide a means to resolve a name clash because unlike a keyword, and macro may be #undefined, or the header that defines it excluded and the internal keyword used directly. Moreover unmodified legacy code will not be broken because by definition it will not include the headers that did not exist at the time of writing

The unadorned keywords have been defined in the language since the language's inception (with the exception of inline and restrict defined since C99), so will not cause a conflict with legacy code symbols. All _Xxxx keywords have been defined at or since C99.

Unlike many languages in common use today, C has been around since the 1970's and standardised since 1989 - there is a huge amount of existing code that must remain compilable on modern compilers while at the same time the language cannot remain unchanged - if it did it might no longer be in such common use.

Tags:

C

Keyword