Funciones en línea estáticas y externas en C

Estoy tratando de aprender la diferencia entre las funciones estáticas y externas en detalle.

Sé la diferencia básica entre las funciones en línea estáticas y externas.

Por favor corrija mi entendimiento si es incorrecto:

  • Las funciones en línea estáticas son visibles solo para la unidad de traducción donde se define.
  • Se puede acceder a las funciones externas en línea en más de una unidad de traducción.
  • Mejor definir funciones en línea en archivos de cabecera
  • No hay diferencia entre las definiciones de funciones en línea estáticas y estáticas.

A continuación se muestra un código de ejemplo donde me quedé atascado sobre el comportamiento.

archivo1.c

#include  #include "file.h" int main(void) { fun1(); return 0; } static inline void fun1(void) { int i; for (i = 0; i < 10; i++) { static int k = 20; printf("Value : %d \n", k++); } } 

archivo2.c

 #include  inline void fun1(void) { int i; int k = 0; for (i = 0; i < 10; i++) { printf("Value : %d \n", k++); } } 

archivo.h

 #ifndef FILE_H #define FILE_H extern inline void fun1(void); #endif 

Cuando compilo el código anterior “gcc file1.c file2.c”, se llamó a fun1 desde file2.c. Esto está claro, ya que fun1 se declara como externo, debe tomar la función externa en file2.c (¿todas las funciones en línea son externas por defecto?).

Pero cuando cambio la función en línea estática a función estática (static void fun1 (void)) en file1.c, fun1 fue llamado desde file1.c. Cuál podría ser la razón ?

También leí como “Si una función en línea se declara con un enlace externo pero no está definida en la misma unidad de traducción, el comportamiento no está definido”. Pero no entendí esto. ¿Es posible explicar esto con el ejemplo anterior?

¿Hay alguna diferencia entre las funciones estáticas y externas en C ++ en comparación con C?

Su código es incorrecto porque no puede declarar una función con extern (que es la extern predeterminada) y luego proporcionar una definición static . El hecho de que se compile en absoluto no indica nada útil.

De n1548 §6.2.2:

Si, dentro de una unidad de traducción, aparece el mismo identificador con enlaces internos y externos, el comportamiento es indefinido.

Entonces, obtienes algo como esto en file1.c :

 // Has external linkage (which is the default!) extern inline void fun1(void); // This would also have external linkage. inline void fun1(void); // This has static linkage. static inline void fun1(void) { ... } 

(Nota: la “vinculación externa” es la predeterminada, pero la extern inline realidad significa algo especial, es diferente de la inline ).

Bam! Comportamiento indefinido. El comstackdor ni siquiera puede darle un mensaje de error, aunque algunos comstackdores parecen dar mensajes de error para esto.

 error: la statement estática de 'func' sigue a la statement no estática

Este error en realidad no tiene nada que ver con el hecho de que la función está en inline . Es un error con o sin inline .

¿Qué hay de esas preguntas?

Las funciones en línea estáticas son visibles solo para la unidad de traducción donde se define.

Esto es cierto para todas las funciones static . Tienen “enlace interno”, por lo que puede tener una static void func(void); en un archivo y una static int func(char *p); completamente diferente static int func(char *p); en un archivo diferente. La inline no hace ninguna diferencia aquí.

Se puede acceder a las funciones externas en línea en más de una unidad de traducción.

Sí, es por eso que no debes ponerlos en archivos de cabecera. Si los coloca en archivos de encabezado, obtendrá múltiples definiciones diferentes de la misma función, a las que se puede acceder desde diferentes unidades de traducción. Esto es un error. En su lugar, coloque el archivo extern inline en extern inline en los archivos de origen, pero solo necesita ser una statement, no una definición.

Mejor definir funciones en línea en archivos de cabecera

No hay ningún punto real para definir una función en línea en ningún otro lugar. Si su función solo se usa en un archivo, márquelo como static y el comstackdor decidirá cómo llamar a la función.

No hay diferencia entre las definiciones de funciones en línea estáticas y estáticas.

Sí, no hay diferencia.

Bueno, técnicamente, no, hay una diferencia porque el comstackdor puede tratar las funciones en static inline manera diferente a las funciones static . Sin embargo, los comstackdores modernos tienden a decidir utilizar funciones en línea utilizando su propio conjunto de reglas, y si una función está en inline no afecta mucho ese proceso.

Bueno, prácticamente hay otra diferencia. Una definición de función en static inline no generará una advertencia en GCC si no se utiliza, pero sí una función static . Esto es para que pueda poner una función en static inline en un archivo de encabezado. Esta es una alternativa a colocar en inline en el archivo de encabezado, que requiere que tengas una extern inline para esa función en algún lugar de tu progtwig. Sin embargo, si el comstackdor decide que preferiría no alinear su función en static inline , ya sea porque piensa que la alineación es peor o porque es imposible, entonces tendrá que hacer una copia separada de esa función en cada archivo en el que se usa.

Entonces, ¿cómo lo haces correctamente?

Nunca declare una función static si tiene una statement previa, no estática. Esto es un error, incluso si se comstack.

No declare una función inline extern en inline extern en un archivo de encabezado. Esto crea una “definición externa” para la función, y solo puede tener una de esas en todo el progtwig.

No declare funciones en inline en los archivos de cabecera sin definirlas. No tiene sentido.

Aquí es cómo querrías hacer esto:

En mylib.h :

 // Provide "inline definition" of the function. inline int times_two(int x) { return x * 2; } 

En mylib.c :

 #include "mylib.h" // Provide "external definition" of the function. extern inline int times_two(int x); 

Esta es la forma estándar de hacer las cosas desde C99. El comstackdor debe tener la libertad de usar la definición interna o la externa, cualquiera que crea que es mejor. Si no tiene una definición externa o tiene más de una, puede obtener un error de enlace, al igual que con las funciones normales.

C ++ tiene sus propias reglas completamente diferentes para las funciones en línea.