5

On leading underscores and names reserved by the C and C++ languages

 1 year ago
source link: https://devblogs.microsoft.com/oldnewthing/20230109-00/?p=107685
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

On leading underscores and names reserved by the C and C++ languages

RaymondChen_5in-150x150.jpg

Raymond Chen

January 9th, 20235 2

THe C and C++ languages reserve certain categories of names for the implementation, which means that you cannot use them in your own code. You can’t use them for variable names, parameter names, classes, methods, macros, whatever.

The rules for C++ are collected in the [lex.name] chapter. The rules for C happen to match the C++ rules, so that makes things easier to remember.

Pattern Conditions
Begins with two underscores Reserved
Begins with underscore and uppercase letter Reserved
Begins with underscore and something else Reserved in global scope (includes macros)

Note that a popular convention of prefixing private members with an underscore runs afoul of these rules if the member name begins with an uppercase letter.

class Widget
{
public:
    Widget();

private:
    int _size; // okay
    void _Toggle(); // not okay
};

The C language does not have namespaces, so it also must reserve names in the global namespace for future expansion. Some names may not be used by symbols with external linkage. You can use them for type names, enumeration members, local variables, and functions or global variables declared with static storage class, but not for extern functions or extern global variables.

// Not allowed: Identifier with external linkage
// beginning with "str" and a lowercase letter.
int strategy;
void strafe() { /* ... */ }

// Allowed: Identifier with internal linkage beginning
// with "str" and a lowercase letter.
static int strawberry;
static void stream_video() { /* ... */ }

Furthermore, if you include the corresponding header file, the names are permitted to be shadowed by function-like macros. This means that if you intend to use a reserved name for someting without external linkage, you must first #undef it or enclose the name in parentheses to prevent it from being treated as a macro.

// Including this header may result in the definition
// of a function-like macro named "strategy".
#include <string.h>

// Must enclose in parentheses to prevent misinterpretation
// as function-like macro.
static void (strategy)();

As of C11, identifiers matching the following regular expressions may not be used for symbols with external linkage. (The list is given in section 7.31: “Future library directions”.) There are also reserved names for type definitions and macros, but I won’t list them here.

Pattern Header
cerfc?[fl]?, cexp2[fl]?,
cexpm1[fl]?, clog1[0p][fl]?,
clog2[fl]?, c[lt]gamma[fl]?
complex.h
is[a-z].*, to[a-z].* ctype.h, wctype.h
atomic_[a-z].* stdatomic.h
str[a-z].* stdlib.h, string.h
mem[a-z].* string.h
wcs[a-z].* string.h, wchar.h
cnd_[a-z].*, mtx_[a-z].*,
thrd_[a-z].*, tss_[a-z].*
thread.h

It may come as a surprise that the C language reserves identifiers like strong, island, and together, but it does.

Bonus chatter: Windows header files have historically not been conscientious about avoiding these reserved names. We’re trying to do better for new headers, but not everyone has gotten the memo.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK