Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does double underscore ( __const) mean in C?

extern int ether_hostton (__const char *__hostname, struct ether_addr *__addr)  __THROW; 

I found the above function definition in /usr/include/netinet/ether.h on a Linux box.

Can someone explain what the double underscores mean in front of const (keyword), addr (identifier) and at last __THROW.

like image 665
Deepak Avatar asked Sep 19 '09 18:09

Deepak


People also ask

What do underscores mean in C?

Standard library implementor cannot freely use names starting with _ but not followed by another underscore nor a capital letter. These names serve as internal identifiers for user code. Any C implementation with static int _foo; in one of its system header is broken; it breaks conforming user code to do so.

Why are underscores used in C?

The programmer uses a single underscore _ as the name for the second argument to the main function. He uses an old style declaration for main() somewhat equivalent to modern int main(int t, int _, char *a) .

What does a double underscore in front of a property of an object mean?

Double underscores are used for fully private variables. According to Python documentation − If your class is intended to be subclassed, and you have attributes that you do not want subclasses to use, consider naming them with double leading underscores and no trailing underscores.

Can underscore be used as a variable in C?

Rules for naming a variable A variable name can only have letters (both uppercase and lowercase letters), digits and underscore. The first letter of a variable should be either a letter or an underscore. There is no rule on how long a variable name (identifier) can be.


2 Answers

In C, symbols starting with an underscore followed by either an upper-case letter or another underscore are reserved for the implementation. You as a user of C should not create any symbols that start with the reserved sequences. In C++, the restriction is more stringent; you the user may not create a symbol containing a double-underscore.

Given:

extern int ether_hostton (__const char *__hostname, struct ether_addr *__addr) __THROW; 

The __const notation is there to allow for the possibility (somewhat unlikely) that a compiler that this code is used with supports prototype notations but does not have a correct understanding of the C89 standard keyword const. The autoconf macros can still check whether the compiler has working support for const; this code could be used with a broken compiler that does not have that support.

The use of __hostname and __addr is a protection measure for you, the user of the header. If you compile with GCC and the -Wshadow option, the compiler will warn you when any local variables shadow a global variable. If the function used just hostname instead of __hostname, and if you had a function called hostname(), there'd be a shadowing. By using names reserved to the implementation, there is no conflict with your legitimate code.

The use of __THROW means that the code can, under some circumstances, be declared with some sort of 'throw specification'. This is not standard C; it is more like C++. But the code can be used with a C compiler as long as one of the headers (or the compiler itself) defines __THROW to empty, or to some compiler-specific extension of the standard C syntax.


Section 7.1.3 of the C standard (ISO 9899:1999) says:

7.1.3 Reserved identifiers

Each header declares or defines all identifiers listed in its associated subclause, and optionally declares or defines identifiers listed in its associated future library directions subclause and identifiers which are always reserved either for any use or for use as file scope identifiers.

— 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.

— Each macro name in any of the following subclauses (including the future library directions) is reserved for use as specified if any of its associated headers is included; unless explicitly stated otherwise (see 7.1.4).

— All identifiers with external linkage in any of the following subclauses (including the future library directions) are always reserved for use as identifiers with external linkage.154)

— Each identifier with file scope listed in any of the following subclauses (including the future library directions) is reserved for use as a macro name and as an identifier with file scope in the same name space if any of its associated headers is included.

No other identifiers are reserved. If the program declares or defines an identifier in a context in which it is reserved (other than as allowed by 7.1.4), or defines a reserved identifier as a macro name, the behavior is undefined.

If the program removes (with #undef) any macro definition of an identifier in the first group listed above, the behavior is undefined.

Footnote 154) The list of reserved identifiers with external linkage includes errno, math_errhandling, setjmp, and va_end.


See also What are the rules about using an underscore in a C++ identifier; a lot of the same rules apply to both C and C++, though the embedded double-underscore rule is in C++ only, as mentioned at the top of this answer.


C99 Rationale

The C99 Rationale says:

7.1.3 Reserved identifiers

To give implementors maximum latitude in packing library functions into files, all external identifiers defined by the library are reserved in a hosted environment. This means, in effect, that no user-supplied external names may match library names, not even if the user function has the same specification. Thus, for instance, strtod may be defined in the same object module as printf, with no fear that link-time conflicts will occur. Equally, strtod may call printf, or printf may call strtod, for whatever reason, with no fear that the wrong function will be called.

Also reserved for the implementor are all external identifiers beginning with an underscore, and all other identifiers beginning with an underscore followed by a capital letter or an underscore. This gives a name space for writing the numerous behind-the-scenes non-external macros and functions a library needs to do its job properly.

With these exceptions, the Standard assures the programmer that all other identifiers are available, with no fear of unexpected collisions when moving programs from one implementation to another5. Note, in particular, that part of the name space of internal identifiers beginning with underscore is available to the user: translator implementors have not been the only ones to find use for “hidden” names. C is such a portable language in many respects that the issue of “name space pollution” has been and is one of the principal barriers to writing completely portable code. Therefore the Standard assures that macro and typedef names are reserved only if the associated header is explicitly included.

5 See §6.2.1 for a discussion of some of the precautions an implementor should take to keep this promise. Note also that any implementation-defined member names in structures defined in <time.h> and <locale.h> must begin with an underscore, rather than following the pattern of other names in those structures.

And the relevant part of the rationale for §6.2.1 Scopes of identifiers is:

Although the scope of an identifier in a function prototype begins at its declaration and ends at the end of that function’s declarator, this scope is ignored by the preprocessor. Thus an identifier in a prototype having the same name as that of an existing macro is treated as an invocation of that macro. For example:

    #define status 23     void exit(int status); 

generates an error, since the prototype after preprocessing becomes

   void exit(int 23); 

Perhaps more surprising is what happens if status is defined

   #define status [] 

Then the resulting prototype is

   void exit(int []); 

which is syntactically correct but semantically quite different from the intent.

To protect an implementation’s header prototypes from such misinterpretation, the implementor must write them to avoid these surprises. Possible solutions include not using identifiers in prototypes, or using names in the reserved name space (such as __status or _Status).

See also P J Plauger The Standard C Library (1992) for an extensive discussion of name space rules and library implementations. The book refers to C90 rather than any later version of the standard, but most of the implementation advice in it remains valid to this day.

like image 136
Jonathan Leffler Avatar answered Sep 28 '22 19:09

Jonathan Leffler


Names with double leading underscores are reserved for use by the implementation. This does not necessarily mean they are internal per se, although they often are.

The idea is, you're not allowed to to use any names starting with __, so the implementation is free to use them in places like macro expansions, or in the names of syntax extensions (e.g. __gcnew is not part of C++, but Microsoft can add it to C++/CLI confident that no existing code should have something like int __gcnew; in it that would stop compiling).

To find out what these specific extensions mean, i.e. __const you'll need to consult the documentation for your specific compiler/platform. In this particular case, you should probably consider the prototype in the documentation (e.g. http://www.kernel.org/doc/man-pages/online/pages/man3/ether_aton.3.html) to be the function's interface and ignore the __const and __THROW decorations that appear in the actual header.

like image 28
Logan Capaldo Avatar answered Sep 28 '22 17:09

Logan Capaldo