¿Por qué algunas funciones en C tienen un prefijo de subrayado?

5 minutos de lectura

Recientemente comencé a aprender redes en C y vi algunas funciones que comienzan con un guión bajo, como _function (), ¿qué significa eso exactamente? También vi esto:

 struct sockaddr_in  {  

__SOCKADDR_COMMON (sin_);  

 in_port_t sin_port;    

 struct in_addr sin_addr;    

 unsigned char sin_zero[sizeof (struct sockaddr) - 

 __SOCKADDR_COMMON_SIZE -  

sizeof (in_port_t) -         

sizeof (struct in_addr)];  

};

¿Qué significa esta parte del código?

__SOCKADDR_COMMON (sin_);

unsigned char sin_zero[sizeof (struct sockaddr) - 

 __SOCKADDR_COMMON_SIZE -  

sizeof (in_port_t) -         

sizeof (struct in_addr)];

  • Consulte también ¿Qué significa doble guión bajo (__const) significa en C? que cita el estándar C sobre el tema de los nombres que comienzan con guiones bajos.

    –Jonathan Leffler

    21/09/2016 a las 20:51


Avatar de usuario de Dietrich Epp
dietrich epp

El prefijo de subrayado está reservado para las funciones y los tipos utilizados por el compilador y la biblioteca estándar. La biblioteca estándar puede usar estos nombres libremente porque nunca entrarán en conflicto con los programas de usuario correctos.

La otra cara de esto es que no se le permite definir nombres que comiencen con un guión bajo.

Bueno, esa es la esencia de la regla. La regla real es esta:

  • No puede definir ningún identificador en el ámbito global cuyos nombres comiencen con un guión bajo, ya que pueden entrar en conflicto con las definiciones de bibliotecas ocultas (privadas). Así que esto no es válido en su código:

    #ifndef _my_header_h_
    #define _my_header_h_ // wrong
    int _x; // wrong
    float _my_function(void); // wrong
    #endif
    

    Pero esto es válido:

    #ifndef my_header_h
    #define my_header_h // ok
    int x; // ok
    float my_function(void) { // ok
        int _x = 3; // ok in function
    }
    struct my_struct {
        int _x; // ok inside structure
    };
    #endif
    
  • No puede definir ningún identificador en ningún ámbito cuyos nombres comiencen con dos guiones bajos, o un guión bajo seguido de una letra mayúscula. Entonces esto no es válido:

    struct my_struct {
        int _Field; // Wrong!
        int __field; // Wrong!
    };
    void my_function(void) {
        int _X; // Wrong!
        int __y; // Wrong!
    }
    

    Pero esto está bien:

    struct my_struct {
        int _field; // okay
    };
    void my_function(void) {
        int _x; // okay
    }
    

En realidad, hay algunas reglas más, solo para complicar las cosas, pero las anteriores son las que se violan con mayor frecuencia y las más fáciles de recordar.

  • @CraigEstey __x y _X pueden ser macros. Pero, esta es una elección de pgmr en cuanto a tal riesgo. El 99,44% de todos esos nombres nunca entrarán en conflicto Y buena suerte para resolver el problema si hay un conflicto. Teniendo en cuenta lo fácil que es poner errores en el código, ¿por qué en la buena Tierra de Dios alguna vez hacer algo que sepa que podría introducir errores imposibles de resolver?

    –Andrew Henle

    21/09/2016 a las 20:31

  • @CraigEstey: entonces tienes suerte. Solo he estado codificando alrededor de 33 años en C, y me he encontrado con algunos problemas desagradables debido al código interno que usa nombres que comienzan con un guión bajo que entra en conflicto con una función del sistema del mismo nombre. Las cosas salen muy mal cuando tu código define int _bind(int x, char y); y el sistema define y llama char *_bind(void *p, char *a, int f); o algo similar, y el código de la biblioteca del sistema termina llamando a su _bind() en lugar del previsto. Eso fue hace unos buenos años (otro milenio, de hecho), pero recuerdo eso y algunos casos similares.

    –Jonathan Leffler

    21/09/2016 a las 20:56

  • @CraigEstey El “_” es una convención lib POSIX Por favor lee 7.1.3 Identificadores reservados de el estándar C: Todos los identificadores que comienzan con un guión bajo y una letra mayúscula u otro guión bajo siempre están reservados para cualquier uso. y 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. Lógicamente, su argumento es el mismo que “Nadé con tiburones mientras estaba cubierto de sangre y no me comieron”. 35 años dices?

    –Andrew Henle

    21/09/2016 a las 21:02

  • @CraigEstey: por eso mencioné ‘otro milenio’: los problemas a menudo son diferentes en estos días, pero la elección de los nombres aún puede causar problemas. Ese es uno de los pocos (menos de media docena, creo) casos de interferencia con nombres de guiones bajos iniciales. (Añadiré, el uso local de _bind() como nombre no fue mi elección, y no causó ningún problema hasta que se transfirió a una nueva plataforma). He tenido más problemas con _t sufijos en tipos que POSIX reserva. En teoría, debe activar activamente la funcionalidad POSIX: ritmo -std=gnu11 que lo hace automáticamente. […continued…]

    –Jonathan Leffler

    21/09/2016 a las 21:34

  • […continuation…] Las reglas POSIX están ahí para que si las violas y duele, no tengas una respuesta. En gran medida, eso también es cierto para las reglas C. También guían a los desarrolladores de sistemas: si siguen las reglas, no dañarán a sus usuarios si esos usuarios también siguen las reglas. El truco es que los novatos miran los encabezados del sistema y piensan “oh, así debe ser como debo escribir mis encabezados también”, e inmediatamente rompen todas las reglas establecidas para evitar que los usuarios y los proveedores del sistema se lastimen entre sí. En última instancia, ese es un problema de educación. SO puede ayudar.

    –Jonathan Leffler

    21/09/2016 a las 21:36

Los guiones bajos iniciales generalmente indican una de 3 cosas:

  1. La definición no es parte del estándar C, por lo que no es portátil.
  2. La definición es interna de una biblioteca o compilador y no debe usarse desde fuera
  3. La definición no debe usarse a la ligera, ya que implica algún riesgo o configuración necesaria que requiere un conocimiento adicional.

En este caso, __SOCKADDR_COMMON es (2): una definición interna, parte de la struct sockaddr_in type, que es al que sueles acceder desde userland.

¿Ha sido útil esta solución?