2010-11-16 14 views
15

No puedo entender el siguiente comportamiento: un encabezado con algunos tipos básicos y otro encabezado en el que utilizo estos tipos en varias funciones. Después comencé a construir clases basadas en mis tipos y funciones definidos. En el encabezado de la función, si dejo la siguiente firma:Vínculo de función en línea

void whateverFunction(parameters) 

El enlazador señala que hay múltiples definiciones de cualquier función. Ahora si lo cambia a:

inline void whateverFunction(parameters) 

el problema de conexión se ha ido y todas las compilaciones y enlaces funcionan bien. Lo que sé sobre inline es que reemplaza cada llamada de función con su código, excepto que es bastante oscuro, así que mi pregunta es:

¿Cómo trata el enlazador las funciones en línea en C++?

+1

Ver ["¿cuál es/son los propósitos de inline?"] (Http://stackoverflow.com/questions/3647053/what-is-are-the-purposes-of-inline) para los detalles , especialmente la parte de la * Regla de una definición *. –

Respuesta

20

Cuando la función en el encabezado no está en línea, múltiples definiciones de esta función (por ejemplo, en varias unidades de traducción) es una violación de las reglas ODR.

Las funciones en línea por defecto tienen un enlace externo. Por lo tanto, como consecuencia de las normas de RLL (dados a continuación), tales definiciones múltiples (por ejemplo, en múltiples unidades de traducción) están bien:

$ 3,2/5- "No puede haber más de un definición de un tipo de clase (Cláusula 9), tipo de enumeración (7.2), inline función con enlace externo (7.1.2), plantilla de clase (Cláusula 14), la plantilla no estático función (14.5.6), miembro de datos estáticos de una plantilla de clase (14.5.1.3), función de miembro de una plantilla de clase (14.5.1.1), o plantilla especialización para la cual algunos parámetros de plantilla no están especificados (14.7, 14.5.5) en un programa siempre que cada definición aparezca en una unidad de traducción diferente, y siempre que las definiciones cumplan los siguientes requisitos . Dada una entidad tal llamado D se define en más de una unidad traducción, entonces

- cada definición de D consistirá de la misma secuencia de tokens; y [...]

La forma en que el enlazador trata las funciones en línea es un detalle del nivel de implementación. Basta con saber que la implementación acepta tales definiciones múltiples dentro de las limitaciones de las reglas ODR

Tenga en cuenta que si la declaración de la función en el encabezado cambia a 'estática en línea ....', entonces la función en línea explícitamente tiene enlace interno y cada unidad de traducción tiene su propia copia de la función estática en línea.

+0

* Las funciones en línea por defecto tienen un enlace externo. *: Encuentro este enunciado engañoso. El código en línea no está vinculado en absoluto, al menos no bajo el nombre de la función. Ver [respuesta de Marcelo] (http://stackoverflow.com/a/4193657/772981). – Jarekczek

+3

En los compiladores modernos, uno puede ver 'inline' como palabra clave para permitir la definición múltiple en lugar de optimizar la pista. El compilador puede decidir no alinear una función en línea, y el vinculador puede elegir cualquiera en las unidades de compilación. El programador debe asegurarse de que una función en línea en las unidades de compilación sea idéntica. De lo contrario, surge un comportamiento indefinido. – jdh8

9

Es posible que el vinculador no vea las funciones en línea en absoluto. Por lo general, se compilan directamente en el código que los llama (es decir, el código se usa en lugar de una llamada a función).

Si el compilador elige no alinear la función (ya que es solo una pista), no estoy seguro, pero creo que el compilador lo emite como una función normal no en línea y de alguna manera lo anota para que el enlazador solo elige la primera copia que ve e ignora las demás.

0

El en línea simplemente oculta el problema. Tener múltiples definiciones señala un problema en alguna parte.

Juste tenga cuidado con la forma de usar sus encabezados. No olvide: - < < #ifndef HEADER_NAME/#define HEADER_NAME/#endif >> para evitar la inclusión múltiple. - No use inclusión indirecta: si usa un tipo en un archivo, agregue el encabezado correspondiente, incluso si otro encabezado en el mismo archivo lo incluye.

Cuestiones relacionadas