C中的双下划线(__const)是什么意思? [英] What does double underscore ( __const) mean in C?

查看:42
本文介绍了C中的双下划线(__const)是什么意思?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我在 Linux 机器上的/usr/include/netinet/ether.h 中找到了上述函数定义.

谁能解释一下 const(关键字)、addr(标识符)和最后的 __THROW 前面的双下划线是什么意思.

解决方案

在 C 中,以下划线开头的符号后跟大写字母或另一个下划线是为实现保留的.作为 C 语言的用户,您不应创建任何以保留序列开头的符号.在 C++ 中,限制更为严格;用户不得创建包含双下划线的符号.

给定:

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

__const 表示法允许(不太可能)使用此代码的编译器支持原型表示法但对 C89 标准关键字 const.autoconf 宏仍然可以检查编译器是否对 const 有工作支持;这段代码可以与没有这种支持的损坏的编译器一起使用.

__hostname__addr 的使用是对你这个头部用户的保护措施.如果您使用 GCC 和 -Wshadow 选项编译,编译器会在任何局部变量遮蔽全局变量时发出警告.如果该函数仅使用 hostname 而不是 __hostname,并且如果您有一个名为 hostname() 的函数,则会出现阴影.通过使用为实现保留的名称,不会与您的合法代码发生冲突.

__THROW 的使用意味着在某些情况下可以使用某种抛出规范"来声明代码.这不是标准 C;它更像是 C++.但是只要头文件之一(或编译器本身)将 __THROW 定义为空,或者定义为标准 C 语法的某些特定于编译器的扩展,代码就可以与 C 编译器一起使用.<小时>

C 标准 (ISO 9899:1999) 的第 7.1.3 节说:

<块引用>

7.1.3 保留标识符

每个标题声明或定义其相关子条款中列出的所有标识符,并且可选地声明或定义在其关联的未来库方向中列出的标识符始终保留用于任何用途或用作文件的子条款和标识符范围标识符.

——所有以下划线和大写字母或其他字母开头的标识符下划线始终保留用于任何用途.

——所有以下划线开头的标识符总是被保留用作标识符在普通名称空间和标签名称空间中都具有文件作用域.

——以下任何子条款中的每个宏名称(包括未来的库如果包含任何关联的标头,则保留用于指定的用途;除非另有明确说明(见 7.1.4).

——在以下任何子条款中具有外部链接的所有标识符(包括未来图书馆方向)始终保留用作外部标识符链接.154)

—在以下任何子条款中列出的具有文件范围的每个标识符(包括未来库方向)保留用作宏名称和标识符如果包含任何关联的标头,则在同一名称空间中的文件范围.

不保留其他标识符.如果程序声明或定义了一个标识符保留它的上下文(7.1.4 允许的除外),或定义保留标识符作为宏名称,行为未定义.

如果程序删除了(用#undef)第一个标识符的任何宏定义上面列出的组,行为未定义.

脚注 154) 带有外部链接的保留标识符列表包括 errnomath_errhandlingsetjmpva_end.

<小时>

另见什么是关于在 C++ 标识符中使用下划线的规则;许多相同的规则适用于 C 和 C++,尽管嵌入的双下划线规则仅适用于 C++,如本答案顶部所述.

<小时>

C99 原理

C99 基本原理 说:

<块引用>

7.1.3 保留标识符

为了给实现者最大的自由度将库函数打包到文件中,所有外部库定义的标识符在托管环境中保留.这意味着,实际上,没有用户提供的外部名称可以匹配库名称,即使用户函数具有 因此,例如,strtod 可以定义在与 printf 相同的目标模块中,而不必担心会发生链接时冲突.同样,strtod 可以调用 printf,或者 printf 可以调用 strtod,无论出于何种原因,不用担心将调用错误的函数.

还为实现者保留了所有以下划线开头的外部标识符,以及所有其他以下划线开头的标识符,后跟大写字母或下划线.这为编写库正常工作所需的大量幕后非外部宏和函数提供了一个命名空间.

除了这些例外,标准向程序员保证所有其他标识符都可用,而不必担心从一个程序移动程序时发生意外冲突实施到另一个5.请特别注意,以下划线开头的内部标识符名称空间的一部分对用户是可用的:翻译实现者并不是唯一发现隐藏"名称的用途的人.C 在许多方面都是一种可移植的语言,以至于名称空间污染"问题一直是编写完全可移植代码的主要障碍之一.因此,该标准确保宏和 typedef 名称仅在明确包含相关标头的情况下才保留.

5 请参阅第 6.2.1 节以讨论实施者为遵守此承诺应采取的一些预防措施.另请注意,在 中定义的结构中的任何实现定义的成员名称必须以下划线开头,而不是跟随这些结构中其他名称的模式.

§6.2.1 标识符范围的相关部分是:

<块引用>

尽管函数原型中标识符的作用域从其声明开始并在函数声明符的末尾结束,但预处理器会忽略该作用域.因此一个标识符在与现有宏同名的原型中,被视为对该宏的调用.例如:

 #define 状态 23无效退出(int状态);

产生错误,因为预处理后的原型变成

 void exit(int 23);

也许更令人惊讶的是如果定义了状态会发生什么

 #define 状态 []

那么得到的原型就是

 void exit(int []);

这在语法上是正确的,但在语义上与意图完全不同.

为了保护实现的标头原型免受此类误解,实现者必须编写它们以避免这些意外.可能的解决方案包括不在原型中使用标识符,或在保留的名称空间中使用名称(例如 __status_Status).

另请参阅 PJ Plauger 标准 C 库 (1992),了解有关名称的广泛讨论空间规则和库实现.这本书提到的是 C90 而不是该标准的任何更高版本,但其中的大部分实现建议至今仍然有效.

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.

解决方案

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.

这篇关于C中的双下划线(__const)是什么意思?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆