¿Por qué incluir guardias no impide definiciones de funciones múltiples?

El vinculador informa sobre el símbolo duplicado en esto:

#ifndef testttt #define testttt void anything(){ std::cout<<"hellooooooo"; } #endif 

Como está dentro de los guardias de inclusión, esperaría que esta función solo se defina una vez. Pero aparentemente no.

Sé que puedo poner la palabra static frente a ella y luego funcionará (lo que todavía encuentro irónico, ya que se supone que la estática le da un enlace interno, pero la función puede usarse desde múltiples archivos cpp).

Así que supongo que mi pregunta de dos partes es: 1) ¿Por qué los guardias de inclusión no impiden definiciones múltiples de esta función como lo hacen para otros elementos de encabezado, y 2) ¿Por qué la palabra static resuelve cuando se supone que estática impide que los nombres visibilidad en otras unidades de traducción? Lo agrego, y realmente puedo llamar a esta función desde cualquier lugar que incluya este archivo de encabezado.

“1) ¿Por qué los guardias de inclusión no impiden definiciones múltiples de esta función como lo hacen para otros elementos de encabezado”

Porque cada unidad de traducción (es decir, archivo .cpp) se procesa por separado y pasa por el mismo condicional. Las unidades de traducción no compartirán las definiciones de preprocesador encontradas por otras unidades de traducción. Esto significa que todas las unidades de traducción que procesarán ese encabezado incluirán una definición para esa función. Por supuesto, el enlazador se quejará de que la misma función tiene múltiples definiciones.

“2) ¿Por qué la palabra estática lo resuelve cuando se supone que estática impide que los nombres se vean en otras unidades de traducción?”

Porque la palabra clave static hace una copia privada de esa función para cada unidad de traducción.

Sin embargo, si desea que se defina esa función en un encabezado compartido, debería marcarla como en inline , lo que resolverá su problema y hará que las protecciones del preprocesador sean innecesarias.

¿Por qué los guardias de inclusión no impiden definiciones múltiples de esta función como lo hacen para otros elementos de encabezado?

El proceso de creación de un ejecutable desde un progtwig C ++ consta de tres etapas:

  1. Preprocesamiento
  2. Comstackcion &
  3. Enlace

Preprocesamiento : las directivas de preprocesador como macros, etc. se reemplazan durante esta etapa.
La comstackción consiste en convertir el código fuente en código de objeto comprobando la semántica del lenguaje.
Vincular es vincular todo el código objeto generado para formar un ejecutable.

Los protectores de cabecera evitan que el contenido del encabezado se incluya varias veces en la misma unidad de traducción durante el preprocesamiento. No impiden que los contenidos se incluyan en diferentes unidades de traducción. Cuando incluye este archivo de encabezado en diferentes unidades de traducción, cada una de estas unidades tendrá una definición de esta función.
El comstackdor comstack cada unidad de traducción por separado para producir un archivo de objeto separado ( .o ), cada uno de esos archivos .o tendrá una copia de esta definición de función. Cuando el enlazador intenta vincularse a la definición de la función en el momento de generar el .exe , encuentra múltiples definiciones de las mismas funciones, causando confusión sobre a cuál vincularse. Para evitar este problema, el estándar define una regla conocida como Regla de definición única (ODR) , que prohíbe varias definiciones de la misma entidad.
Como puede ver, incluir la definición de función en el archivo de encabezado e incluir ese archivo de encabezado en varias unidades de traducción infringe el ODR.
La forma habitual de hacerlo es proporcionar la statement en el archivo de encabezado y la definición en uno y solo un archivo fuente.

¿Por qué la palabra estática lo resuelve cuando se supone que estática impide que los nombres sean visibles en otras unidades de traducción?

Cuando agrega la palabra clave static a la función, cada unidad de traducción tendrá su propia copia de la función. Por defecto, las funciones tienen un enlace externo, pero static fuerza a la función a tener un enlace interno . Por lo tanto, la definición no es visible para diferentes unidades de traducción. Cada instancia de dicha función se trata como una función separada (la dirección de cada función es diferente ) y cada instancia de estas funciones tiene sus propias copias de variables locales estáticas y literales de cadena. Tenga en cuenta que esto aumenta considerablemente el tamaño de su ejecutable.


Si desea incluir la definición de la función en un archivo de encabezado. Hay 3 formas de hacerlo:

  1. Marque la función como en inline o
  2. Marque la función como static o
  3. Ponga la función en un espacio de nombre sin nombre.

Tenga en cuenta que #1 y #2 hacen lo mismo que se menciona en la segunda respuesta anterior.
Con el n. #3 el estándar relaja el ODR para las funciones en línea y permite que cada unidad de traducción tenga su propia definición ( siempre que todas las definiciones sean las mismas ).

Entonces, si realmente quiere poner una definición de función en el encabezado #1 es la forma correcta de hacerlo.

1) ¿Por qué los guardias de inclusión no impiden definiciones múltiples de esta función como lo hacen para otros elementos de encabezado,

Incluya guardias para evitar la inclusión múltiple del encabezado en la misma unidad de traducción. Sin embargo, no impide múltiples definiciones: si el encabezado está incluido en una unidad de traducción múltiple, habrá un error de definición múltiple, porque la función está definida en cada unidad de traducción, y dado que tiene una vinculación externa , toda la unidad de traducción puede ver la definición de todas las demás unidades de traducción. Para evitar este error, solo debe proporcionar la statement en el encabezado y proporcionar la definición en UN archivo .cpp .

Lea sobre la regla de una definición (ODR) y la vinculación externa .

2) ¿Por qué la palabra estática lo resuelve cuando se supone que estática impide que los nombres sean visibles en otras unidades de traducción?

Porque static hace que la función sea interna para cada unidad de traducción. Eso es lo que significa vinculación interna : otra unidad de traducción no puede ver la definición.