简体   繁体   English

C中的双下划线(__const)是什么意思?

[英]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.我在 Linux 机器上的 /usr/include/netinet/ether.h 中找到了上述函数定义。

Can someone explain what the double underscores mean in front of const (keyword), addr (identifier) and at last __THROW.有人可以解释一下 const(关键字)、addr(标识符)和最后的 __THROW 前面的双下划线是什么意思。

In C, symbols starting with an underscore followed by either an upper-case letter or another underscore are reserved for the implementation.在 C 中,以下划线开头的符号后跟大写字母或另一个下划线是为实现保留的。 You as a user of C should not create any symbols that start with the reserved sequences.作为 C 语言的用户,您不应创建任何以保留序列开头的符号。 In C++, the restriction is more stringent;在 C++ 中,限制更为严格; 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 . __const表示法允许使用此代码的编译器支持原型表示法但没有正确理解 C89 标准关键字const的可能性(有些不太可能)。 The autoconf macros can still check whether the compiler has working support for const ; autoconf宏仍然可以检查编译器是否支持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. __hostname__addr的使用是对你这个头部用户的一种保护措施。 If you compile with GCC and the -Wshadow option, the compiler will warn you when any local variables shadow a global variable.如果您使用 GCC 和-Wshadow选项进行编译,则当任何局部变量-Wshadow全局变量时,编译器会警告您。 If the function used just hostname instead of __hostname , and if you had a function called hostname() , there'd be a shadowing.如果该函数仅使用hostname而不是__hostname ,并且您有一个名为hostname()的函数,则会有阴影。 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'. __THROW的使用意味着在某些情况下可以使用某种“抛出规范”来声明代码。 This is not standard C;这不是标准 C; it is more like C++.它更像是 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.但是只要头文件之一(或编译器本身)将__THROW定义为空,或者定义为标准 C 语法的某些特定于编译器的扩展,代码就可以与 C 编译器一起使用。


Section 7.1.3 of the C standard (ISO 9899:1999) says: C 标准 (ISO 9899:1999) 的第 7.1.3 节说:

7.1.3 Reserved identifiers 7.1.3 保留标识符

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).除非另有明确说明(见 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) 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.如果程序在保留标识符的上下文中声明或定义标识符(7.1.4 允许的情况除外),或将保留标识符定义为宏名称,则行为未定义。

If the program removes (with #undef ) any macro definition of an identifier in the first group listed above, the behavior is undefined.如果程序删除(使用#undef )上面列出的第一组中的标识符的任何宏定义,则行为未定义。

Footnote 154) The list of reserved identifiers with external linkage includes errno , math_errhandling , setjmp , and va_end .脚注 154) 具有外部链接的保留标识符列表包括errnomath_errhandlingsetjmpva_end


See also What are the rules about using an underscore in a C++ identifier ;另请参阅在 C++ 标识符中使用下划线的规则是什么 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.许多相同的规则适用于 C 和 C++,尽管嵌入的双下划线规则仅适用于 C++,如本答案顶部所述。


C99 Rationale C99 基本原理

The C99 Rationale says: C99 基本原理说:

7.1.3 Reserved identifiers 7.1.3 保留标识符

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.因此,例如, strtod可以在与printf相同的对象模块中定义,而不必担心会发生链接时冲突。 Equally, strtod may call printf , or printf may call strtod , for whatever reason, with no fear that the wrong function will be called.同样,无论出于何种原因, strtod可以调用printf ,或者printf可以调用strtod ,而不必担心会调用错误的函数。

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 another 5 .除了这些例外,标准向程序员保证所有其他标识符都是可用的,在将程序从一个实现移动到另一个实现时不必担心意外冲突5 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. C 在许多方面都是一种可移植的语言,以至于“名称空间污染”问题一直是编写完全可移植代码的主要障碍之一。 Therefore the Standard assures that macro and typedef names are reserved only if the associated header is explicitly included.因此,标准确保只有在显式包含关联的标头时才保留宏和typedef名称。

5 See §6.2.1 for a discussion of some of the precautions an implementor should take to keep this promise. 5请参阅第 6.2.1 节以讨论实施者为遵守此承诺应采取的一些预防措施。 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.另请注意, <time.h><locale.h>定义的结构中的任何实现定义的成员名称必须以下划线开头,而不是遵循这些结构中其他名称的模式。

And the relevant part of the rationale for §6.2.1 Scopes of identifiers is: §6.2.1 标识符范围的基本原理的相关部分是:

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 ).可能的解决方案包括不在原型中使用标识符,或使用保留名称空间中的名称(例如__status_Status )。

See also PJ Plauger The Standard C Library (1992) for an extensive discussion of name space rules and library implementations.另请参阅 PJ Plauger The Standard C Library (1992) 以获取对名称空间规则和库实现的广泛讨论。 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.本书引用的是 C90 而不是该标准的任何更高版本,但其中的大部分实现建议直到今天仍然有效。

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 (eg __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).这个想法是,不允许使用任何以__开头的名称,因此实现可以在宏扩展等地方或在语法扩展的名称中自由使用它们(例如__gcnew不是 C++ 的一部分,而是 Microsoft可以将它添加到 C++/CLI,确信现有代码不应该有像int __gcnew;这样的东西int __gcnew;在其中会停止编译)。

To find out what these specific extensions mean, ie __const you'll need to consult the documentation for your specific compiler/platform.要了解这些特定扩展的含义,即__const您需要查阅特定编译器/平台的文档。 In this particular case, you should probably consider the prototype in the documentation (eg 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.在这种特殊情况下,您可能应该将文档中的原型(例如http://www.kernel.org/doc/man-pages/online/pages/man3/ether_aton.3.html )视为函数的接口,并且忽略实际标题中出现的__const__THROW装饰。

按照某些库的约定,这表示特定符号供内部使用,而不打算成为库公共 API 的一部分。

The underscore in __const means that this keyword is a compiler extension and using it is not portable (The const keyword was added to C in a later revision, 89 I think). __const 中的下划线意味着这个关键字是一个编译器扩展并且使用它是不可移植的(const 关键字是在以后的修订版中添加到 C 中的,我认为是 89)。 The __THROW is also some kind of extension, I assume that it gets defined to some __attribute__(something) if gcc is used, But I'm not sure on that and too lazy to check. __THROW 也是某种扩展,我假设如果使用 gcc,它会被定义为某些 __attribute__(something),但我不确定这一点,也懒得检查。 The __addr can mean anything the programmer wanted it to mean, It's just a name. __addr 可以表示程序员想要它表示的任何内容,它只是一个名称。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM