extern int ether_hostton (__const char *__hostname, struct ether_addr *__addr)
__THROW;
Encontré la definición de función anterior en /usr/include/netinet/ether.h en una caja de Linux.
¿Alguien puede explicar qué significan los guiones bajos dobles delante de const (palabra clave), addr (identificador) y, por último, __THROW?
En C, los símbolos que comienzan con un guión bajo seguido de una letra mayúscula u otro guión bajo están reservados para la implementación. Usted, como usuario de C, no debe crear ningún símbolo que comience con las secuencias reservadas. En C++, la restricción es más estricta; usted, el usuario, no puede crear un símbolo que contenga un guión bajo doble.
Dado:
extern int ether_hostton (__const char *__hostname, struct ether_addr *__addr)
__THROW;
Él __const
la notación está ahí para permitir la posibilidad (algo improbable) de que un compilador con el que se usa este código admita notaciones prototipo pero no tiene una comprensión correcta de la palabra clave estándar C89 const
. Él autoconf
las macros aún pueden verificar si el compilador tiene soporte funcional para const
; este código podría usarse con un compilador roto que no tenga ese soporte.
El uso de __hostname
y __addr
es una medida de protección para usted, el usuario del encabezado. Si compila con GCC y el -Wshadow
opción, el compilador le advertirá cuando cualquier variable local sombree una variable global. Si la función utilizada sólo hostname
en vez de __hostname
y si tuvieras una función llamada hostname()
, habría un sombreado. Al usar nombres reservados para la implementación, no hay conflicto con su código legítimo.
El uso de __THROW
significa que el código puede, en algunas circunstancias, declararse con algún tipo de ‘especificación de lanzamiento’. Esto no es C estándar; es más como C++. Pero el código se puede usar con un compilador C siempre que uno de los encabezados (o el compilador mismo) defina __THROW
para vaciar, o para alguna extensión específica del compilador de la sintaxis estándar de C.
La sección 7.1.3 de la norma C (ISO 9899:1999) dice:
7.1.3 Identificadores reservados
Cada encabezado declara o define todos los identificadores enumerados en su subcláusula asociada y, opcionalmente, declara o define los identificadores enumerados en su subcláusula de direcciones de biblioteca futura asociada e identificadores que siempre están reservados para cualquier uso o para uso como identificadores de alcance de archivo.
— Todos los identificadores que comienzan con un guión bajo y una letra mayúscula u otro guión bajo siempre se reservan para cualquier uso.
— Todos los identificadores que comienzan con un guión bajo siempre se reservan para su uso como identificadores con ámbito de archivo en los espacios de nombres ordinarios y de etiquetas.
— Cada nombre de macro en cualquiera de las siguientes subcláusulas (incluidas las direcciones futuras de la biblioteca) se reserva para su uso como se especifica si se incluye cualquiera de sus encabezados asociados; a menos que se indique explícitamente lo contrario (ver 7.1.4).
— Todos los identificadores con enlace externo en cualquiera de las siguientes subcláusulas (incluidas las futuras instrucciones de la biblioteca) siempre se reservan para su uso como identificadores con enlace externo.154)
— Cada identificador con alcance de archivo enumerado en cualquiera de las siguientes subcláusulas (incluidas las futuras instrucciones de la biblioteca) se reserva para su uso como nombre de macro y como identificador con alcance de archivo en el mismo espacio de nombres si se incluye alguno de sus encabezados asociados.
No se reservan otros identificadores. Si el programa declara o define un identificador en un contexto en el que está reservado (aparte de lo permitido por 7.1.4), o define un identificador reservado como un nombre de macro, el comportamiento no está definido.
Si el programa elimina (con #undef
) cualquier definición de macro de un identificador en el primer grupo mencionado anteriormente, el comportamiento no está definido.
Nota al pie 154) La lista de identificadores reservados con enlace externo incluye errno
, math_errhandling
,
setjmp
y va_end
.
Consulte también ¿Cuáles son las reglas sobre el uso de un guión bajo en un identificador de C++? muchas de las mismas reglas se aplican tanto a C como a C++, aunque la regla incrustada de doble guión bajo solo está en C++, como se menciona en la parte superior de esta respuesta.
Justificación C99
Él Justificación C99 dice:
7.1.3 Identificadores reservados
Para dar a los implementadores la máxima libertad para empaquetar las funciones de la biblioteca en archivos, todos los identificadores externos definidos por la biblioteca se reservan en un entorno alojado. Esto significa, en efecto, que ningún nombre externo proporcionado por el usuario puede coincidir con los nombres de biblioteca, ni siquiera si la función de usuario tiene la misma especificación. Así, por ejemplo, strtod
puede definirse en el mismo módulo de objeto que printf
, sin temor a que se produzcan conflictos en el tiempo de enlace. Igualmente, strtod
puede llamar printf
o printf
puede llamar strtod
por el motivo que sea, sin temor a que se llame a la función equivocada.
También están reservados para el implementador todos identificadores externos que comienzan con un guión bajo y todos los demás identificadores que comienzan con un guión bajo seguido de una letra mayúscula o un guión bajo. Esto brinda un espacio de nombres para escribir las numerosas funciones y macros no externas detrás de escena que una biblioteca necesita para hacer su trabajo correctamente.
Con estas excepciones, el Estándar asegura al programador que todos los demás los identificadores están disponibles, sin temor a colisiones inesperadas al mover programas de una implementación a otra5. Tenga en cuenta, en particular, que parte del espacio de nombres de los identificadores internos que comienzan con un guión bajo está disponible para el usuario: los implementadores de traductores no han sido los únicos en encontrar uso para nombres “ocultos”. C es un lenguaje tan portátil en muchos aspectos que el problema de la “contaminación del espacio de nombres” ha sido y es una de las principales barreras para escribir código completamente portátil. Por lo tanto, la Norma asegura que macro y typedef
los nombres se reservan solo si el encabezado asociado se incluye explícitamente.
5 Ver §6.2.1 para una discusión de algunas de las precauciones que un implementador debe tomar para mantener esta promesa. Tenga en cuenta también que cualquier nombre de miembro definido por la implementación en estructuras definidas en <time.h>
y <locale.h>
debe comenzar con un guión bajo, en lugar de seguir el patrón de otros nombres en esas estructuras.
Y la parte relevante de la justificación de §6.2.1 Alcances de los identificadores es:
Aunque el alcance de un identificador en un prototipo de función comienza en su declaración y termina al final del declarador de esa función, el preprocesador ignora este alcance. Así, un identificador en un prototipo que tenga el mismo nombre que el de una macro existente se trata como una invocación de esa macro. Por ejemplo:
#define status 23
void exit(int status);
genera un error, ya que el prototipo después del preprocesado se vuelve
void exit(int 23);
Quizás más sorprendente es lo que sucede si se define el estado
#define status []
Entonces el prototipo resultante es
void exit(int []);
lo cual es sintácticamente correcto pero semánticamente bastante diferente de la intención.
Para proteger los prototipos de encabezado de una implementación de tales interpretaciones erróneas, el implementador debe escribirlos para evitar estas sorpresas. Las posibles soluciones incluyen no usar identificadores en prototipos o usar nombres en el espacio de nombres reservado (como __status
o _Status
).
Véase también PJ Plauger La biblioteca estándar de C (1992) para una discusión extensa de las reglas del espacio de nombres y las implementaciones de la biblioteca. El libro se refiere a C90 en lugar de a cualquier versión posterior del estándar, pero la mayoría de los consejos de implementación siguen siendo válidos hasta el día de hoy.
Los nombres con guiones bajos dobles al principio están reservados para que los use la implementación. Esto no significa necesariamente que sean internos per se, aunque a menudo lo son.
La idea es que no está permitido usar ningún nombre que comience con __
por lo que la implementación es libre de usarlos en lugares como expansiones de macros o en los nombres de extensiones de sintaxis (p. ej. __gcnew
no es parte de C++, pero Microsoft puede agregarlo a C++/CLI con la confianza de que ningún código existente debería tener algo como int __gcnew;
en él que dejaría de compilar).
Para averiguar qué significan estas extensiones específicas, es decir, __const
deberá consultar la documentación de su compilador/plataforma específico. En este caso particular, probablemente debería considerar el prototipo en la documentación (por ejemplo, http://www.kernel.org/doc/man-pages/online/pages/man3/ether_aton.3.html) para ser la interfaz de la función e ignorar el __const
y __THROW
decoraciones que aparecen en el encabezado real.
Por convención en algunas bibliotecas, esto indica que un símbolo en particular es para uso interno y no pretende ser parte de la API pública de la biblioteca.
El guión bajo en __const significa que esta palabra clave es una extensión del compilador y su uso no es portátil (creo que la palabra clave const se agregó a C en una revisión posterior, 89). El __THROW también es una especie de extensión, supongo que se define en algún __atributo__(algo) si se usa gcc, pero no estoy seguro de eso y soy demasiado perezoso para verificar. El __addr puede significar cualquier cosa que el programador quisiera que significara, es solo un nombre.
Hay un resumen muy, muy bueno de las reglas para los identificadores reservados aquí: stackoverflow.com/questions/228783/…
– Michael Burr
20 de septiembre de 2009 a las 0:46
Técnicamente, x-ref son ‘identificadores reservados para C++’, pero (ahora) también hay buena información del estándar C.
–Jonathan Leffler
20 de septiembre de 2009 a las 1:27