58 votes

variables constantes ne fonctionnant pas dans l'en-tête

si je définis mes variables constantes dans mon en-tête comme ceci ...

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

Je reçois l'erreur suivante

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

mais si je supprime ces constantes de l'en-tête et les mets dans le document qui inclut l'en-tête comme ceci ...

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

Ça marche

Quelqu'un a-t-il une idée de ce que je pourrais faire de mal ??

Merci

138voto

AndreyT Points 139512

Le problème, c'est que vous définissez les objets avec une liaison externe dans le fichier d'en-tête. Évidemment, une fois que vous inclure ce fichier d'en-tête dans plusieurs unités de traduction, vous aurez de multiples définitions de l'objet même avec une liaison externe, ce qui est une erreur.

La bonne façon de le faire dépend de votre intention.

(1) Vous pouvez mettre vos définitions dans le fichier d'en-tête, mais assurez-vous qu'ils ont interne de liaison.

En C qui aurait besoin d'une explicite 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 est facultatif (parce qu'en C++ const des objets ont une liaison interne par défaut)

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

(2) Ou vous pouvez mettre de la simple non-définition des déclarations dans le fichier d'en-tête et de mettre les définitions dans un (et un seul) de la mise en œuvre de fichier

Les déclarations dans l' en-tête de fichier doit inclure explicitement extern et pas d'initialiseur

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

et les définitions dans une mise en œuvre de fichier doit se présenter comme suit

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

(explicite extern dans les définitions est facultatif, si les déclarations faites précéder les définitions).

La méthode que vous choisissez dépend de votre intention.

La première méthode permet au compilateur d'optimiser le code, car il peut voir la valeur réelle de la constante dans chaque unité de traduction. Mais en même temps, sur le plan conceptuel-vous obtenir distinct, indépendant objets constants dans chaque unité de traduction. Par exemple, &PI évaluera à une adresse différente dans chaque unité de traduction.

La deuxième méthode crée véritablement mondial des constantes, c'est à dire unique constante des objets qui sont partagées par l'ensemble du programme. Par exemple, &PI évaluera à la même adresse, dans chaque unité de traduction. Mais dans ce cas, le compilateur ne peut voir les valeurs réelles dans une et une seule unité de traduction, ce qui pourrait empêcher les optimisations.

9voto

Carl Norum Points 114072

extern signifie que la définition "réelle" de la variable est ailleurs et que le compilateur doit avoir confiance que les choses se brancheront au moment du lien. Avoir la définition en ligne avec les extern est bizarre et c'est ce qui modifie votre programme. Si vous voulez qu'ils soient extern , définissez-les exactement une fois ailleurs dans votre programme.

5voto

Jerry Coffin Points 237758

L' extern classe de stockage pour eux, c'est presque certainement la cause du problème que vous avez vu. Si vous l'enlevez, le code sera probablement très bien (du moins à cet égard).

Edit: je viens de remarquer que vous avez marqués ce que C et C++. À cet égard, le C et le C++ sont très différents (mais de messages d'erreur, vous êtes apparemment la compilation en C++, pas du C). En C++, vous souhaitez supprimer l' extern, parce que (par défaut) const variables ont l' static classe de stockage. Cela signifie que chaque fichier source (unité de traduction) aura son propre "copie" de la variable, et il n'y aura pas de conflit entre les définitions dans les différents fichiers. Puisque vous êtes (probablement) en utilisant uniquement les valeurs, pas les traiter comme des variables, le fait d'avoir plusieurs "copies" ne fera pas de mal rien -, aucun d'entre eux sera d'espace de stockage alloué.

En C, extern est assez différent, et la suppression de la extern ne fera aucune différence, car ils seront en extern par défaut. Dans ce cas, vous avez vraiment besoin pour initialiser les variables dans un seul endroit, et de les déclarer extern dans l'en-tête. Alternativement, vous pouvez ajouter l' static classe de stockage C++ ajoute par défaut lorsque vous/si vous supprimez l' extern de l'en-tête.

1voto

Peter Alexander Points 31990

Il semble que l'en-tête de fichier est inclus plusieurs fois. Vous avez besoin d'ajouter des gardes.

En haut de chaque fichier d'en-tête, vous devriez avoir quelque chose comme:

#ifndef MY_HEADER_FILE_NAME_H
#define MY_HEADER_FILE_NAME_H

...

// at end of file
#endif

Si vous êtes à l'aide de g++ ou MSVC, alors vous pouvez simplement ajouter:

#pragma once

En haut de chaque fichier d'en-tête, mais ce n'est pas 100% portable.

Aussi, vous ne devez pas définir des constantes dans les fichiers d'en-tête, seulement déclarer:

// In header file
extern const int my_const;


// In one source file
const int my_const = 123;

1voto

TheJacobTaylor Points 2982

Vous devez déclarer le contants dans l'en-tête et ensuite, de définir dans un de vos fichiers de code. Si vous ne déclarez pas n'importe où, alors il existe un éditeur de liens erreur lorsqu'il tente de lier la déclaration à la définition actuelle. Vous pouvez aussi sortir avec l'aide de #ifdef déclarations pour avoir une définition dans l'en-tête.

Assurez-vous qu'ils sont déclarés dans un en-tête qui est compris par tout le monde qui en a besoin et assurez-vous qu'ils sont définis exactement une fois.

Jacob

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X