¿Cuál es la diferencia entre la función "estática" y "estática en línea"?

123

Los dos IMO hacen que la función tenga un alcance de la unidad de traducción solamente.

¿Cuál es la diferencia entre la función "estática" y "estática en línea"?

¿Por qué debería inlinecolocarse en un archivo de encabezado, no en un .carchivo?

new_perl
fuente

Respuestas:

109

inlineindica al compilador que intente incrustar el contenido de la función en el código de llamada en lugar de ejecutar una llamada real.

Para funciones pequeñas que se llaman con frecuencia que pueden marcar una gran diferencia de rendimiento.

Sin embargo, esto es solo una "pista", y el compilador puede ignorarlo, y la mayoría de los compiladores intentará "en línea" incluso cuando no se use la palabra clave, como parte de las optimizaciones, cuando sea posible.

por ejemplo:

static int Inc(int i) {return i+1};
.... // some code
int i;
.... // some more code
for (i=0; i<999999; i = Inc(i)) {/*do something here*/};

Este ciclo cerrado realizará una llamada a la función en cada iteración, y el contenido de la función en realidad es significativamente menor que el código que el compilador necesita poner para realizar la llamada. inlineesencialmente le indicará al compilador que convierta el código anterior en un equivalente de:

 int i;
 ....
 for (i=0; i<999999; i = i+1) { /* do something here */};

Saltarse la llamada a la función real y regresar

Obviamente, este es un ejemplo para mostrar el punto, no una pieza de código real.

staticse refiere al alcance. En C significa que la función / variable solo puede usarse dentro de la misma unidad de traducción.

littleadv
fuente
44
No, se staticrefiere al alcance. En C significa que la función / variable solo puede usarse dentro de la misma unidad de traducción.
littleadv
8
También es importante tener en cuenta que el código declarado como en línea pertenece al encabezado, donde el código fuente normal (sin plantilla) no puede ir en los encabezados sin causar múltiples errores de redefinición. Así que incluso cuando se declara algo en línea, incluso si los elige compilador que no se inline, todavía hay una redefinición de múltiples comportamientos evitando el mandato estándar que se activa.
Voidstar
13
@VoidStar En realidad static(con o sin inline) puede estar en el encabezado perfectamente bien, no veo ninguna razón por la que no. Las plantillas son para C ++, esta pregunta es sobre C.
littleadv
2
@littleadv: la razón principal para poner las definiciones de funciones en los archivos de encabezado es hacerlas alineables, por lo que marcarlas explícitamente inlinees un buen estilo, en mi opinión
Christoph
9
En realidad inlineno le indica al compilador que haga ningún intento de alineación. Simplemente le permite al programador incluir el cuerpo de la función en múltiples unidades de traducción sin violación de ODR. Un efecto secundario de esto es que es hace posible que el compilador, cuando sería inline la función, que lo hacen realmente.
Ruslan
96

Por defecto, una definición en línea solo es válida en la unidad de traducción actual.

Si 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.

Si la clase de almacenamiento es static, el identificador tiene un enlace interno y la definición en línea es invisible en otras unidades de traducción.

Si la clase de almacenamiento no está especificada, la definición en línea solo es visible en la unidad de traducción actual, pero el identificador todavía tiene un enlace externo y se debe proporcionar una definición externa en una unidad de traducción diferente. El compilador es libre de usar la definición en línea o externa si la función se llama dentro de la unidad de traducción actual.

Como el compilador es libre de incorporar (y no incluir) cualquier función cuya definición sea visible en la unidad de traducción actual (y, gracias a las optimizaciones de tiempo de enlace, incluso en diferentes unidades de traducción, aunque el estándar C realmente no tiene en cuenta eso), para la mayoría de los propósitos prácticos, no hay diferencia entre las definiciones staticy las static inlinefunciones.

El inlineespecificador (como la registerclase de almacenamiento) es solo una pista del compilador, y el compilador es libre de ignorarlo por completo. Los compiladores no optimizadores que cumplen con los estándares solo tienen que respetar sus efectos secundarios, y los compiladores optimizadores harán estas optimizaciones con o sin sugerencias explícitas.

inliney registerno son inútiles, ya que le indican al compilador que arroje errores cuando el programador escribe un código que haría imposibles las optimizaciones: una inlinedefinición externa no puede hacer referencia a identificadores con enlace interno (ya que estos no estarían disponibles en una unidad de traducción diferente) o defina variables locales modificables con una duración de almacenamiento estática (ya que no compartirían el estado entre las unidades de traducción), y no puede tomar direcciones de registervariables calificadas.

Personalmente, también uso la convención para marcar staticlas definiciones de funciones dentro de los encabezados inline, ya que la razón principal para poner las definiciones de funciones en los archivos de encabezado es hacer que sean integrables.

En general, solo uso definiciones de static inlinefunciones y static constobjetos además de las externdeclaraciones dentro de los encabezados.

Nunca he escrito una inlinefunción con una clase de almacenamiento diferente de static.

Christoph
fuente
8
Esta es la respuesta correcta. Cualquier respuesta que se refiera inlinecomo si realmente se aplicara a la alineación es engañosa y podría decirse que es incorrecta. Ningún compilador moderno lo utiliza como una sugerencia para alinearlo o requerirlo para permitir la inserción de una función.
Tyg13
1
votó por "usar la convención para marcar definiciones de funciones estáticas en encabezados en línea".
John Z. Li
21

Según mi experiencia con GCC, lo sé staticy static inlinedifiere en una forma en que el compilador emite advertencias sobre las funciones no utilizadas. Más precisamente, cuando declara la staticfunción y no se usa en la unidad de traducción actual, el compilador genera una advertencia sobre la función no utilizada, pero puede inhibir esa advertencia al cambiarla a static inline.

Por lo tanto, tiendo a pensar que staticdebería usarse en unidades de traducción y me beneficiaré del compilador de verificación adicional para encontrar funciones no utilizadas. Y static inlinedebe usarse en archivos de encabezado para proporcionar funciones que puedan estar alineadas (debido a la ausencia de enlaces externos) sin emitir advertencias.

Lamentablemente no puedo encontrar ninguna evidencia para esa lógica. Incluso a partir de la documentación de GCC no pude concluir que inlineinhibe las advertencias de funciones no utilizadas. Agradecería si alguien compartiera enlaces a la descripción de eso.

ony
fuente
Mmm, todavía obtuve warning: unused function 'function' [clang-diagnostic-unused-function]una static inlinefunción al clang-tidycompilar con (v8.0.1), que se usa en otra unidad de traducción. Pero definitivamente, esta es una de las mejores explicaciones y razones para combinar static& inline!
DrumM
6

En C, staticsignifica que la función o variable que defina solo se puede usar en este archivo (es decir, la unidad de compilación)

Entonces, static inlinesignifica la función en línea que solo se puede utilizar en este archivo.

EDITAR:

La unidad de compilación debe ser La Unidad de Traducción

shengy
fuente
2
O en palabras elegantes: tiene un enlace interno.
K-balloon el
@AlokSave: ¿Hay alguna diferencia entre la unidad de compilación y la unidad de traducción ? Si es así, ¿cuál es más apropiado en el contexto del lenguaje C ++?
legends2k
Creo que the compile unites algo que escribí por error, no existe tal cosa, la terminología real estranslation unit
shengy
Su respuesta no está completa porque se usa principalmente en archivos de encabezado, entre unidades de traducción.
DrumM
5

Una diferencia que no está en el nivel del lenguaje sino en el nivel de implementación popular: ciertas versiones de gcc eliminarán las static inlinefunciones no referenciadas de la salida de forma predeterminada, pero mantendrán las staticfunciones simples incluso si no están referenciadas. No estoy seguro de a qué versiones se aplica esto, pero desde un punto de vista práctico significa que puede ser una buena idea usar siempre inlinepara staticfunciones en encabezados.

R .. GitHub DEJA DE AYUDAR AL HIELO
fuente
¿Qué hay de usar inlineen definición? ¿También implica no usarlo para externfunciones?
new_perl
¿Sigue siendo cierto con la versión reciente de GCC? Su respuesta sería mucho más interesante si tuviera un ejemplo y enumerara qué versión de GCC lo hace.
Z boson
@Zboson: No tengo esa información fácilmente disponible y no tengo tiempo para configurar y probar muchas versiones de gcc en este momento, pero estoy de acuerdo en que sería útil tener información. Probablemente podría encontrar cuándo gcc comenzó a optimizar las funciones / objetos estáticos no utilizados al observar el historial attribute((used))y su uso para permitir que asm haga referencia a staticfunciones y datos que de otro modo no estarían referenciados .
R .. GitHub DEJA DE AYUDAR A HIELO