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

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

我在Linux机器上的/usr/include/netinet/ether.h中find了上面的函数定义。

有人可以解释在const(关键字),addr(标识符)和最后__THROW前双重下划线的含义。

在C中,以下划线开始的符号,后跟一个大写字母或另一个下划线,将被保留用于实现。 您作为C的用户不应该创build任何以保留序列开头的符号。 在C ++中,限制更严格; 您用户可能不会创build包含双下划线的符号。

鉴于:

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

__const表示法允许使用此代码的编译器支持原型表示法,但对C89标准关键字const没有正确理解的可能性(某种程度上不太可能)。 autoconfmacros仍然可以检查编译器是否支持const ; 这个代码可以用于没有支持的破碎的编译器。

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

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


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

7.1.3保留的标识符

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

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

– 以下划线开始的所有标识符始终保留用作普通标签名称空间和标签名称空间中具有文件范围的标识符。

– 如果包含任何相关的标题,则下列任何子条款(包括未来的图书馆方向)中的每个macros名称都被保留以供指定使用; 除非另有明确说明(见7.1.4)。

– 以下任何子条款(包括未来的图书馆方向)中的所有带有外部链接的标识符总是保留用作外部链接的标识符。 154)

– 包含以下任何子条款(包括未来库指示)中列出的文件范围的每个标识符都被保留用作macros名称,并且如果包含其任何相关头文件,则将其用作具有相同名称空间中的文件范围的标识符。

没有其他标识符被保留。 如果程序在保留的上下文中声明或定义了一个标识符(7.1.4中允许的除外),或者将一个保留的标识符定义为macros名称,则行为是不确定的。

如果程序删除(使用#undef )上面列出的第一组中的标识符的任何macros定义,则行为是未定义的。

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


另请参见有关在C ++标识符中使用下划线的规则 ; 很多相同的规则适用于C和C ++,尽pipeembedded式双下划线规则仅在C ++中,正如本答案的顶部所述。

带有双前导下划线的名称保留供实施使用。 这并不一定意味着它们本身就是内在的,尽pipe它们通常是。

这个想法是,你不能使用以__开头的任何名字,所以这个实现可以在macros扩展或者扩展名的地方使用(例如__gcnew不是C ++的一部分,但是微软可以将其添加到C ++ / CLI确信没有现有的代码应该有像int __gcnew;在这将停止编译)。

要找出这些特定扩展名的含义,即__const您需要查阅您的特定编译器/平台的文档。 在这种情况下,您应该将文档中的原型(如http://www.kernel.org/doc/man-pages/online/pages/man3/ether_aton.3.html )作为函数的接口,忽略出现在实际标题中的__const__THROW装饰。

根据一些图书馆的惯例,这表明一个特定的符号是供内部使用的,并不打算成为图书馆公共API的一部分。

__const中的下划线表示这个关键字是一个编译器扩展,并且使用它不是可移植的(在我以后的版本中const关键字被添加到C中)。 __THROW也是某种扩展,我假设它被定义为一些__attribute __(某些东西),如果使用gcc的话,但是我不确定,也懒得去检查。 __addr可以表示程序员想要的任何东西,这只是一个名字。