2010-03-06 6 views

Respuesta

11

Recuerde que incluir algo de un encabezado no es diferente a solo escribirlo directamente en el archivo fuente. Así que estar en un encabezado no hace diferencia en lo que respecta al compilador; nunca supo que estaba allí.

Así que cuando define una función en un archivo de encabezado e incluye ese archivo de encabezado en un archivo, es como si acabara de escribir la función directamente en el archivo. Así que ahora la pregunta es, "¿el compilador elige en línea cosas basadas en heurística?"

La respuesta es "depende del compilador". La norma no ofrece garantías sobre lo que se incluye o no. Dicho esto, cualquier compilador moderno será extremadamente inteligente sobre lo que incluye, probablemente con heurística.

Sin embargo, llegamos a un punto interesante. Imagine que tiene una función en un encabezado e incluye ese encabezado en múltiples archivos de origen. A continuación, tendrá múltiples definiciones de la función, a través de las unidades de traducción, y esto viola la regla de una definición. Ergo, obtendrás errores de compilación. (El error del enlazador suele ser algo así como: "Error, la función x ya está definida en y") Lo que puede hacer es usar la palabra clave inline y ya no violará el ODR. Por favor, __inline no es estándar. Contrariamente a su publicación, generalmente es una extensión del compilador que fuerza en línea, no lo insinúa. inline es la palabra clave estándar, que originalmente fue pensada para insinuar la inclusión. Como dices, la mayoría de los compiladores modernos lo ignoran por completo en ese aspecto y su único propósito en la actualidad es darles a las cosas un vínculo interno.

+0

¿Alguna idea sobre qué heurística utiliza un compilador moderno como g ++ en su decisión? es decir, ¿está en la línea de "en línea cualquier función donde la proporción de sitios de llamadas a bytes-en-función-cuerpo es menor que X"? ¿O es algo más sutil? –

+0

@Jeremy: No tengo idea, aunque estoy bastante interesado ahora que lo mencionas. Podré mirar esta noche. Sospecho que es bastante complicado. – GManNickG

+1

@GMan: el bit sobre la vinculación interna es incorrecto. 'inline' no tiene ningún efecto en el enlace. En C++, una función declarada como 'inline' tiene una vinculación externa (a menos que se declare específicamente' static'), al igual que cualquier otra función. El ODR para funciones en línea permite específicamente múltiples definiciones en diferentes unidades de traducción, aunque el enlace sea externo. – AnT

2

Elegirá en función de la heurística. Asegúrese de declararlo como en línea explícitamente; de ​​lo contrario, puede obtener un error de enlace de símbolo duplicado si incluye el encabezado en más de una unidad de compilación.

4

Desde el C++ FAQ Lite:

No importa cómo se designa una función como en línea, que es una solicitud para que se le permite al compilador de ignorar: que podría cilindros en línea ampliar algunos, todos o ninguno de las llamadas a una función en línea.

2

Si definir una función con enlace externo en un archivo de cabecera e incluirlo en más de una unidad de traducción, obtendrá error de compilación (más precisamente: erorr enlazador) por la violación de una regla de definición (ODR). Entonces, la respuesta es "no": el compilador no tomará la definición de una función en un archivo de encabezado como una sugerencia de la alineación y no lo excusará de observar los requisitos de ODR. No solo se garantiza que estas funciones estén en línea, sino que lo más probable es que su programa ni siquiera compile.

Para definir una función en un archivo de encabezado y salirse con la suya, tiene que asignarle un enlace interno (declararlo static y terminar con una función separada en cada unidad de traducción) o declararlo explícitamente inline.

En cuanto a la heurística ...Los compiladores modernos normalmente consideran virtualmente cualquier función para inline (aplicando heurística), independientemente de dónde esté definida y si está explícitamente declarada inline o no.

1

No hay magia sobre las funciones en los encabezados. El compilador ni siquiera sabe si una función está definida en un encabezado o no. (Dado que los encabezados son solo copiar/pegar en el archivo fuente, puede definirlo en un encabezado, pero el compilador simplemente lo ve como parte de la unidad de traducción)

También hay dos significados diferentes de "en línea" para tenga en cuenta:

una función puede ser inlined como se define por la norma C++: Esto se hace ya sea prefijando la función con la palabra clave inline, o si es una función miembro, definiendo en-lugar dentro de la definición de clase.

El efecto de esto es que

  • informar al enlazador que se puede encontrar la definición de función en varios archivos, y debería simplemente en silencio unirlos en vez de lanzar un error
  • hacen que sea más fácil para el compilador para realizar la optimización optimización.

El inlining optimización por el contrario, es simplemente el acto de la sustitución de una llamada a la función por el cuerpo de la función de llamada, lo que significa que esta optimización se aplica realmente a llamar a los sitios, no a las funciones. Una función se puede llamar normalmente en algunos lugares, pero en otra parte. Una llamada a función está en línea cuando el compilador así lo desee, y es mejor separarla conceptualmente por completo del primer significado de "en línea".

El compilador aplicará la optimización de alineación si, cuándo y dónde lo desee. Utiliza mucha heurística para esto. Es más probable que las funciones más pequeñas estén en línea. Si determina que un sitio de llamada específico se ejecutará con la suficiente frecuencia, es más probable que esté en línea. En definitiva, la heurística que utiliza se basa en "mejorará o degradará el rendimiento". Y generalmente es un mejor juez de esto que los seres humanos, por lo que no debería necesitar saber qué heurística precisa utiliza. Inventar demasiado solo dañará el rendimiento.

Cuestiones relacionadas