ventajas tipos metodos las funciones funcion clases c inline c99

tipos - ¿Cuál es el uso de la palabra clave `inline` en C?



tipos de funciones en c++ (5)

Como una palabra "Inline" dice "En" "Línea", agregar esta palabra clave a la función afecta al programa en tiempo de ejecución, cuando se compila un programa, el código escrito en el interior de la función se pega debajo de la llamada de función, ya que las llamadas de función son más costosas que código en línea, por lo que este optimiza el código. Por lo tanto, static inline void f (void) {} ​​y static void f (void) {}, en esta palabra clave inline hace diferencia en tiempo de ejecución. Pero cuando la función tiene demasiadas líneas de código, no afectará el tiempo de ejecución. Si agrega estática antes de la función, el tiempo de vida de la función es el tiempo de vida de todo el programa. Y el uso de esa función está restringido solo a ese archivo. Para saber sobre extern puede consultar: Efectos de la palabra clave externa en las funciones de C

Leí varias preguntas en stackoverflow sobre inline en C, pero todavía no lo tengo claro.

  1. static inline void f(void) {} no tiene ninguna diferencia práctica con static void f(void) {} .
  2. inline void f(void) {} en C no funciona como el método C ++. ¿Cómo funciona en C?
  3. Lo que realmente hace extern inline void f(void); ¿hacer?

Realmente nunca encontré un uso de la palabra clave en inline en mis programas de C, y cuando veo esta palabra clave en el código de otras personas, casi siempre está en static inline , en la que no veo diferencia con solo static .


Desde 6.7.4 Especificadores de funciones en las especificaciones C11.

6 Una función declarada con un especificador de función en línea es una función en línea. Hacer una función una función en línea sugiere que las llamadas a la función sean lo más rápidas posible. 138) La medida en que dichas sugerencias son efectivas está definida por la implementación . 139)

138) Al utilizar, por ejemplo, una alternativa al mecanismo de llamada de función habitual, como la sustitución en línea . La sustitución en línea no es una sustitución textual , ni crea una nueva función. Por lo tanto, por ejemplo, la expansión de una macro utilizada dentro del cuerpo de la función usa la definición que tenía en el punto en que aparece el cuerpo de la función, y no donde se llama la función; y los identificadores se refieren a las declaraciones en el ámbito donde se produce el cuerpo. Del mismo modo, la función tiene una sola dirección, independientemente del número de definiciones en línea que se producen además de la definición externa.

139) Por ejemplo, una implementación nunca puede realizar una sustitución en línea , o solo puede realizar sustituciones en línea a llamadas en el alcance de una declaración en línea.

Sugiere al compilador que esta función se usa ampliamente y solicita la velocidad en la invocación de esta función. Pero con el compilador inteligente moderno, esto puede ser más o menos irrelevante, ya que los compiladores pueden decidir si una función debe estar en línea y pueden ignorar la solicitud en línea de los usuarios, ya que los compiladores modernos pueden decidir muy eficazmente cómo invocar las funciones.

static inline void f(void) {} no tiene ninguna diferencia práctica con static void f(void) {} .

Así que sí, con compiladores modernos la mayoría del tiempo ninguno. Con cualquier compilador no hay diferencias de salida prácticas / observables.

inline void f(void) {} en C no funciona como el método C ++. ¿Cómo funciona en C?

Una función que está en línea en cualquier lugar debe estar en línea en cualquier lugar en C ++ y el vinculador no se queja error de definición múltiple (la definición debe ser la misma).

Lo que realmente hace extern inline void f (void); ¿hacer?

Esto proporcionará enlace externo a f . Debido a que la f puede estar presente en otra unidad de compilación, un compilador puede elegir un mecanismo de llamada diferente para acelerar las llamadas o puede ignorar la inline completo.


El código de CA se puede optimizar de dos maneras: para el tamaño del código y para el tiempo de ejecución.

funciones en línea:

gcc.gnu.org dice,

Al declarar una función en línea, puede indicar a GCC que realice llamadas a esa función más rápido. Una forma en que GCC puede lograr esto es integrar el código de esa función en el código para sus llamadores. Esto hace que la ejecución sea más rápida al eliminar la sobrecarga de la función-llamada; Además, si alguno de los valores de los argumentos reales es constante, sus valores conocidos pueden permitir simplificaciones en el momento de la compilación, por lo que no es necesario incluir todo el código de la función en línea. El efecto sobre el tamaño del código es menos predecible; El código objeto puede ser más grande o más pequeño con la función de alineación, dependiendo del caso particular.

Entonces, le dice al compilador que construya la función en el código donde se usa con la intención de mejorar el tiempo de ejecución.

Si declara funciones pequeñas, como configurar / borrar una marca o algún cambio de bit que se realiza repetidamente, en inline , puede hacer una gran diferencia de rendimiento con respecto al tiempo, pero al costo del tamaño del código.

En línea no estática y en línea estática

De nuevo refiriéndose a gcc.gnu.org ,

Cuando una función en línea no es estática, el compilador debe asumir que puede haber llamadas de otros archivos de origen; Como un símbolo global solo se puede definir una vez en cualquier programa, la función no debe definirse en los otros archivos de origen, por lo que las llamadas no se pueden integrar. Por lo tanto, una función en línea no estática siempre se compila por sí misma de la manera habitual.

en línea externa?

Una vez más, gcc.gnu.org , lo dice todo:

Si especifica tanto inline como extern en la definición de la función, entonces la definición se usa solo para inline. En ningún caso, la función se compila por sí sola, ni siquiera si hace referencia a su dirección explícitamente. Dicha dirección se convierte en una referencia externa, como si solo hubiera declarado la función y no la hubiera definido.

Esta combinación de inline y extern tiene casi el efecto de una macro. La forma de usarlo es colocar una definición de función en un archivo de encabezado con estas palabras clave y colocar otra copia de la definición (sin línea y externa) en un archivo de biblioteca. La definición en el archivo de encabezado hace que la mayoría de las llamadas a la función estén en línea. Si queda algún uso de la función, se refieren a la copia única en la biblioteca.

Para resumirlo:

  1. Para inline void f(void){} , la definición en inline solo es válida en la unidad de traducción actual.
  2. Para static inline void f(void) {} Como la clase de almacenamiento es static , el identificador tiene un enlace interno y la definición en inline es invisible en otras unidades de traducción.
  3. Para la extern inline void f(void); Dado que la clase de almacenamiento es extern , el identificador tiene un enlace externo y la definición en línea también proporciona la definición externa.

Nota: cuando hablo de archivos .c y archivos .h en esta respuesta, asumo que ha presentado su código correctamente, es decir, los archivos .c solo incluyen archivos .h . La distinción es que un archivo .h puede incluirse en varias unidades de traducción.

static inline void f(void) {} no tiene ninguna diferencia práctica con static void f(void) {} .

En ISO C, esto es correcto. Son idénticos en comportamiento (¡suponiendo que no los vuelvas a declarar de manera diferente en la misma TU, por supuesto!) El único efecto práctico puede ser hacer que el compilador se optimice de manera diferente.

inline void f(void) {} en C no funciona como el método C ++. ¿Cómo funciona en C? Lo que realmente hace extern inline void f(void); ¿hacer?

Esto se explica por esta respuesta y también este hilo .

En ISO C y C ++, puede usar libremente inline void f(void) {} en los archivos de encabezado, ¡aunque por diferentes motivos!

En ISO C, no proporciona una definición externa en absoluto. En ISO C ++ proporciona una definición externa; sin embargo, C ++ tiene una regla adicional (que C no), que si hay varias definiciones externas de una función en inline , el compilador las ordena y selecciona una de ellas.

extern inline void f(void); en un archivo .c en ISO C se debe emparejar con el uso de inline void f(void) {} en los archivos de encabezado. Hace que la definición externa de la función se emita en esa unidad de traducción. Si no hace esto, entonces no hay una definición externa, por lo que puede obtener un error de enlace (no se especifica si alguna llamada particular de f vincula a la definición externa o no).

En otras palabras, en ISO C puede seleccionar manualmente a dónde va la definición externa; o suprimir completamente la definición externa mediante el uso de static inline todas partes; pero en ISO C ++, el compilador elige si y dónde irá una definición externa.

En GNU C, las cosas son diferentes (más sobre esto más adelante).

Para complicar aún más las cosas, GNU C ++ le permite escribir en static inline y extern inline en extern inline en código de C ++ ... No me gustaría adivinar qué hace exactamente eso.

Realmente nunca encontré un uso de la palabra clave en línea en mis programas de C, y cuando veo esta palabra clave en el código de otras personas, casi siempre está en línea estática

Muchos programadores no saben lo que están haciendo y simplemente organizan algo que parece funcionar. Otro factor aquí es que el código que estás viendo podría haber sido escrito para GNU C, no ISO C.

En GNU C , la inline simple se comporta inline manera diferente a la ISO C. En realidad, emite una definición visible externamente, por lo que tener un archivo .h con una función simple en inline incluida desde dos unidades de traducción provoca un comportamiento indefinido.

Entonces, si el codificador quiere proporcionar la sugerencia de optimización en inline en GNU C, entonces se requiere una static inline . Debido a que static inline funciona tanto en ISO C como en GNU C, es natural que las personas terminen conformándose con eso y vean que parece funcionar sin errores.

, en la que no veo diferencia con solo estática.

La diferencia está solo en la intención de proporcionar una sugerencia de optimización de velocidad sobre el tamaño al compilador. Con los compiladores modernos esto es superfluo.


Una función donde todas las declaraciones (incluida la definición) mencionan en línea y nunca externamente.
Debe haber una definición en la misma unidad de traducción. El estándar se refiere a esto como una definición en línea.
No se emite ningún código de objeto independiente, por lo que esta definición no puede llamarse desde otra unidad de traducción.

En este ejemplo, todas las declaraciones y definiciones usan en línea pero no extern:

// a declaration mentioning inline inline int max(int a, int b); // a definition mentioning inline inline int max(int a, int b) { return a > b ? a : b; }

Here hay una referencia que puede darle más claridad sobre las funciones en línea en C y también sobre el uso de inline y extern.