6.7.4 Especificadores de funciones
Una nueva característica de C99: la inline
palabra clave, adaptada de C ++, es un especificador de función que solo se puede usar en declaraciones de función. Es útil para optimizaciones de programas que requieren que la definición de una función sea visible en el sitio de una llamada. (Tenga en cuenta que el Estándar no intenta especificar la naturaleza de estas optimizaciones).
La visibilidad está asegurada si la función tiene un enlace interno, o si tiene un enlace externo y la llamada está en la misma unidad de traducción que la definición externa. En estos casos, la presencia de la
inline
palabra clave en una declaración o definición de la función no tiene ningún efecto más allá de indicar una preferencia de que las llamadas de esa función deben optimizarse con preferencia a las llamadas de otras funciones declaradas sin la inline
palabra clave.
La visibilidad es un problema para una llamada de una función con enlace externo donde la llamada está en una unidad de traducción diferente de la definición de la función. En este caso, la inline
palabra clave permite que la unidad de traducción que contiene la llamada también contenga una definición local o en línea de la función.
Un programa puede contener una unidad de traducción con una definición externa, una unidad de traducción con una definición en línea y una unidad de traducción con una declaración pero sin definición para una función. Las llamadas en la última unidad de traducción utilizarán la definición externa como de costumbre.
Una definición en línea de una función se considera una definición diferente a la definición externa. Si se func
produce una llamada a alguna función con enlace externo donde una definición en línea es visible, el comportamiento es el mismo que si la llamada se hiciera a otra función, por ejemplo
__func
, con enlace interno. Un programa conforme no debe depender de la función que se llame. Este es el modelo en línea en el estándar.
Un programa conforme no debe depender de la implementación usando la definición en línea, ni puede depender de la implementación usando la definición externa. La dirección de una función es siempre la dirección correspondiente a la definición externa, pero cuando esta dirección se usa para llamar a la función, se puede usar la definición en línea. Por lo tanto, es posible que el siguiente ejemplo no se comporte como se esperaba.
inline const char *saddr(void)
{
static const char name[] = "saddr";
return name;
}
int compare_name(void)
{
return saddr() == saddr(); // unspecified behavior
}
Dado que la implementación puede usar la definición en línea para una de las llamadas saddr
y usar la definición externa para la otra, no se garantiza que la operación de igualdad se evalúe a 1 (verdadero). Esto muestra que los objetos estáticos definidos dentro de la definición en línea son distintos de su objeto correspondiente en la definición externa. Esto motivó la restricción en contra incluso de definir un no const
objeto de este tipo.
Inlining se agregó al estándar de tal manera que se puede implementar con la tecnología de enlazador existente, y un subconjunto de C99 inlining es compatible con C ++. Esto se logró al requerir que se especificara exactamente una unidad de traducción que contiene la definición de una función en línea como la que proporciona la definición externa para la función. Debido a que esa especificación consiste simplemente en una declaración que carece de la inline
palabra clave o contiene ambas inline
y extern
, también será aceptada por un traductor de C ++.
Inlining en C99 extiende la especificación de C ++ de dos maneras. Primero, si una función se declara
inline
en una unidad de traducción, no es necesario declararla inline
en todas las demás unidades de traducción. Esto permite, por ejemplo, una función de biblioteca que debe incluirse dentro de la biblioteca, pero está disponible solo a través de una definición externa en otro lugar. La alternativa de usar una función contenedora para la función externa requiere un nombre adicional; y también puede afectar negativamente al rendimiento si un traductor no realiza la sustitución en línea.
En segundo lugar, el requisito de que todas las definiciones de una función en línea sean "exactamente iguales" se reemplaza por el requisito de que el comportamiento del programa no debe depender de si una llamada se implementa con una definición en línea visible, o la definición externa, de un función. Esto permite que una definición en línea se especialice para su uso dentro de una unidad de traducción particular. Por ejemplo, la definición externa de una función de biblioteca puede incluir alguna validación de argumentos que no es necesaria para las llamadas realizadas desde otras funciones en la misma biblioteca. Estas extensiones ofrecen algunas ventajas; y los programadores que estén preocupados por la compatibilidad pueden simplemente cumplir con las reglas más estrictas de C ++.
Nótese que es no apropiado para implementaciones para proporcionar las definiciones de las funciones en línea de la biblioteca estándar en las cabeceras estándar ya que esto puede romper algo de código legado que redeclares funciones de la librería estándar después incluyendo sus cabeceras. La inline
palabra clave está destinada únicamente a proporcionar a los usuarios una forma portátil de sugerir la inserción de funciones. Debido a que los encabezados estándar no necesitan ser portátiles, las implementaciones tienen otras opciones como:
#define abs(x) __builtin_abs(x)
u otros mecanismos no portátiles para incorporar funciones de biblioteca estándar.