si debo definir mi constante varibles en mi cabecera como este…

extern const double PI = 3.1415926535;
extern const double PI_under_180 = 180.0f / PI;
extern const double PI_over_180 = PI/180.0f;

Me sale el siguiente error

1>MyDirectX.obj : error LNK2005: "double const PI" (?[email protected]@3NB) already defined in main.obj
1>MyDirectX.obj : error LNK2005: "double const PI_under_180" (?[email protected]@3NB) already defined in main.obj
1>MyDirectX.obj : error LNK2005: "double const PI_over_180" (?[email protected]@3NB) already defined in main.obj
1>MyGame.obj : error LNK2005: "double const PI" (?[email protected]@3NB) already defined in main.obj
1>MyGame.obj : error LNK2005: "double const PI_under_180" (?[email protected]@3NB) already defined in main.obj
1>MyGame.obj : error LNK2005: "double const PI_over_180" (?[email protected]@3NB) already defined in main.obj

pero Si puedo quitar esas constantes de la cabecera y los puso en el documento en el que está incluido el encabezado como este…

const double PI = 3.1415926535;
const double PI_under_180 = 180.0f / PI;
const double PI_over_180 = PI/180.0f;

Funciona

¿Alguien tiene Idea de lo que pueda estar haciendo mal ??

Gracias

  • Probablemente, usted debe escribir 180.0 en lugar de 180.0f puesto que usted está tratando con dobles en lugar de carrozas. También cambiar el nombre de PI a algo más exclusivo. PI se utiliza en muchas bibliotecas como una macro y si usted lo usa, usted puede obtener impar resultados.
  • Perder el extern y vas a estar bien.
  • No en C, donde const objetos tienen vinculación externa por defecto, lo que significa que extern no cambia nada.
InformationsquelleAutor numerical25 | 2010-02-24

10 Comentarios

  1. 129

    El problema es que definir objetos con la vinculación externa en el archivo de encabezado. Como era de esperar, una vez que incluir ese archivo de encabezado en múltiples unidades de traducción, obtendrá varias definiciones de un mismo objeto con la vinculación externa, lo cual es un error.

    La manera correcta de hacer esto depende de su intención.

    1. Usted puede poner sus definiciones en el archivo de encabezado, pero asegúrese de que tienen interna de vinculación.

      En C, lo que requeriría un explícito static

      static const double PI = 3.1415926535; 
      static const double PI_under_180 = 180.0f / PI; 
      static const double PI_over_180 = PI/180.0f; 

      En C++ static es opcional (porque en C++ const objetos tienen vinculación interna por defecto)

      const double PI = 3.1415926535; 
      const double PI_under_180 = 180.0f / PI; 
      const double PI_over_180 = PI/180.0f; 
    2. O usted puede poner mera no la definición de las declaraciones en el archivo de encabezado y poner el definiciones en uno (y sólo uno) archivo de implementación

      Las declaraciones en el encabezado archivo debe incluir una explícita extern y no inicializador

      extern const double PI; 
      extern const double PI_under_180; 
      extern const double PI_over_180; 

      y definiciones en uno aplicación del archivo debe tener la siguiente manera

      const double PI = 3.1415926535; 
      const double PI_under_180 = 180.0f / PI; 
      const double PI_over_180 = PI/180.0f; 

      (explícita extern en las definiciones es opcional, si las anteriores declaraciones que preceden a las definiciones en la misma unidad de traducción).

    El método que usted elija depende de su intención.

    El primer método hace que sea más fácil para el compilador para optimizar el código, ya que se puede ver el valor real de la constante en cada unidad de traducción. Pero, al mismo tiempo, conceptualmente usted obtener independientes de objetos constantes en cada unidad de traducción. Por ejemplo, &PI evaluará a una dirección diferente en cada unidad de traducción.

    El segundo método, se crea realmente global constantes, es decir, la única constante de los objetos que son compartidos por la totalidad del programa. Por ejemplo, &PI va a evaluar a la misma dirección en cada unidad de traducción. Pero en este caso el compilador sólo puede ver los valores reales en una y sólo una unidad de traducción, que podría impedir optimizaciones.


    A partir de C++17 de obtener la tercera opción, que tipo de combina «lo mejor de ambos mundos»: en línea de variables. En línea de las variables pueden ser de forma segura definidos en los archivos de encabezado a pesar de tener vinculación externa

    inline extern const double PI = 3.1415926535; 
    inline extern const double PI_under_180 = 180.0f / PI; 
    inline extern const double PI_over_180 = PI/180.0f; 

    En este caso, usted consigue una constante con nombre inicializador de objeto cuyo valor es visible en todas las unidades de traducción. Y, al mismo tiempo, el objeto tiene vinculación externa, es decir, no tiene una dirección global de identidad (&PI es el mismo en todas las unidades de traducción).

    Concedido, algo así como que sólo podrían ser necesarias para algunos de los exóticos a los efectos de (la mayoría de los casos de uso en C++ llamada para la primera variante), pero la función está allí.

    • +1. Sólo quería mencionar que en C a static const variable no es una expresión de la constante de como iba a necesitar para el tamaño de una matriz, por ejemplo. Supongo que por eso #defines son más populares en la C.
    • +1 para una buena descripción y enseñanza de mí algo que yo no sabía: «en C++ constante objetos tienen vinculación interna por defecto»
    • Sí, pero esto sobre todo se convierte en un problema con la forma de constantes. El impacto sobre la no-integral constante de los objetos es insignificante, si es que existe.
    • +1 gran descripción de lo que está sucediendo y soluciones.
    • el amor de encontrar respuestas completas en Stackoverflow que son generalmente de mejor lectura de la doco.
  2. 9

    extern significa que la «verdadera» definición de la variable está en otro lugar, y el compilador debe confiar en que las cosas van a conectar en tiempo de vínculo. Tener la definición en línea con el extern es raro y es lo que fotográficos de su programa. Si quieres a extern, acaba de definir exactamente una vez en otras partes de su programa.

  3. 5

    La extern de clase de almacenamiento para ellos es casi seguro que la causa del problema que estamos viendo. Si se quita, el código estará bien (al menos en este sentido).

    Edit: acabo de darme cuenta de que se ha etiquetado como C y C++. En este sentido, C y C++ son realmente muy diferentes (pero de los mensajes de error, estás al parecer compilar como C++, no C). En C++, desea quitar el extern, porque (por defecto) const las variables tienen el static de clase de almacenamiento. Eso significa que cada archivo de origen (unidad de traducción) tendrá su propia «copia» de la variable, y no habrá ningún conflicto entre las definiciones en diferentes archivos. Puesto que usted es (probablemente) sólo a partir de los valores, y no los trata como variables, el tener varias «copias» no me duele nada, ninguno de ellos se le asignará un espacio de almacenaje.

    En C, extern es bastante diferente, y la eliminación de la extern no hará ninguna diferencia real, ya que van a ser extern por defecto. En este caso, usted realmente necesita para inicializar las variables en exactamente un lugar, y declarar externas en el encabezado. Alternativamente, usted puede agregar el static clase de almacenamiento que C++ se agrega de forma predeterminada cuando/si se quita la extern de la cabecera.

  4. 2

    El problema es que se están inicializando las variables en el archivo de encabezado; esto crea un la definición de declaración, que se repite en cada archivo que incluye la cabecera,por lo tanto la definición múltiple de error.

    Desea un no-definición de la declaración (no inicializador) en el archivo de encabezado, y poner la declaración de definición en uno de los archivos de implementación.

    • si usamos #ifndef #define al inicio del archivo de encabezado y todavía definir el las constantes, no se que será suficiente?
    • Qué quieres decir con el uso de macros en lugar de const variables?
  5. 2

    Una gran cantidad de respuestas incorrectas a continuación. Los que son correctos son los de decirle a usted para quitar el extern como sellibitze también ha dicho en su comentario, son correctos.

    Debido a que estos están declaradas como const, no hay ningún problema, la definición que figura en el encabezado. C++ incluirá una constante para un sistema incorporado en la tipo a menos que usted intente tomar su dirección (un puntero a una constante), en cuyo caso se creará una instancia con static vinculación, entonces usted puede también obtener varios casos en módulos separados, pero a menos que usted espera que todos los punteros a la misma const tienen la misma dirección, esto no es un problema.

    • MSVC tener un comportamiento diferente de lo que usted espera. Usted puede conseguir la duplicación de símbolos si se declara una variable como const en un encabezado. Usted necesita usar tanto static const para garantizar la vinculación interna. Tal vez es un bug del compilador.
    • en la pregunta se informó que se trabajó sin estática. El comportamiento de C no diferentes, pero dado que el código en cuestión vinculada, debe de haber utilizado la compilación de C++. La pregunta es, sin embargo etiquetado en C y C++, así que podría decirse que yo debería haber cubierto tanto, pero la pregunta no era acerca de las diferencias entre C y C++, así que supongo que simplemente mal etiquetados. La pregunta es de 7 años de edad, por lo que no garantiza la actualización.
  6. 1

    Deberá declarar la contants en el encabezado y, a continuación, definir en uno de los archivos de código. Si no se declara ningún lugar, entonces no es un enlazador de error cuando se intenta vincular la declaración a la definición real. Usted también puede conseguir lejos con usar #ifdef declaraciones a tiene una única definición en la cabecera.

    Asegúrese de que se haya declarado en un encabezado que se incluye por todo el mundo que lo necesita y asegúrese de que están definidos exactamente una vez.

    Jacob

  7. 1

    Si quieres definir constantes en los archivos de encabezado, el uso de static const. Si utiliza extern, el enlazador es el derecho a quejarse acerca de las múltiples definiciones, porque cada una de ellas archivo de código fuente de suministro de la memoria para la variable si se asigna un valor.

  8. 1

    Parece que el archivo de encabezado es llegar incluido varias veces. Usted necesita agregar los guardias.

    En la parte superior de cada archivo de encabezado usted debe tener algo como:

    #ifndef MY_HEADER_FILE_NAME_H
    #define MY_HEADER_FILE_NAME_H
    
    ...
    
    //at end of file
    #endif

    Si usted está usando g++ o MSVC entonces usted puede agregar:

    #pragma once

    En la parte superior de cada archivo de encabezado, pero que no es 100% portable.

    También, no se debe definir constantes en los archivos de encabezado, sólo declaran:

    //In header file
    extern const int my_const;
    
    
    //In one source file
    const int my_const = 123;
    • Incluyen los guardias sólo proteger contra múltiples inclusión en el mismo archivo. La falta de ellos va a producir un problema en tiempo de compilación. Él está en un problema en el momento de enlazar, porque de intentar definir los mismos símbolos una vez cada uno en varios archivos.
    • Me dirigí a que en mi respuesta.
  9. 0

    en la declaración mundial const dentro de cabecera hace que cada unidad de compilación, incluyendo este hader tendrá propias definiciones definiciones globales con el mismo nombre.
    A continuación, el enlazador no le gusta eso.

    Si Usted realmente necesita estos en la cabecera, a continuación, probablemente Usted debe declarar como estática.

  10. 0

    Una vieja pregunta, en efecto, sino una respuesta útil es la que falta.

    Es posible engañar a MSVC en la aceptación de las constantes estáticas en los encabezados simplemente envolviendo los de un «dummy» de la plantilla de clase:

    template <typename Dummy = int>
    struct C {
         static const double Pi;
    };
    
    template <typename Dummy = int>
    const double C<Dummy>::Pi = 3.14159;

    Ahora, C<>::PI se puede acceder desde otros lugares. No redefinición de las protestas; constante es directamente accesible en cada una de las unidades de compilación sin fantasía enlace optimización del tiempo. Macro se puede rodar a cabo para embellecer este enfoque (aunque las macros son malas).

    • ¿Existen desventajas de utilizar este método?
    • Un poco de reglas sintácticas desventaja, como se mencionó tendrán que referirse a Pi como C<>::Pi en todo el código. Pero luego, suelta constantes globales son mejor evitar de todos modos (por lo MathConst<>::Pi es sólo ligeramente peor que MathConst::Pi).

Dejar respuesta

Please enter your comment!
Please enter your name here