Le sens des deux m'échappe.
Le sens des deux m'échappe.
Réponses:
Une déclaration introduit un identifiant et décrit son type, que ce soit un type, un objet ou une fonction. Une déclaration est ce dont le compilateur a besoin pour accepter les références à cet identifiant. Ce sont des déclarations:
extern int bar;
extern int g(int, int);
double f(int, double); // extern can be omitted for function declarations
class foo; // no extern allowed for type declarations
Une définition instancie / implémente réellement cet identifiant. C'est ce dont l'éditeur de liens a besoin pour lier des références à ces entités. Ce sont des définitions correspondant aux déclarations ci-dessus:
int bar;
int g(int lhs, int rhs) {return lhs*rhs;}
double f(int i, double d) {return i+d;}
class foo {};
Une définition peut être utilisée à la place d'une déclaration.
Un identifiant peut être déclaré aussi souvent que vous le souhaitez. Ainsi, ce qui suit est légal en C et C ++:
double f(int, double);
double f(int, double);
extern double f(int, double); // the same as the two above
extern double f(int, double);
Cependant, il doit être défini exactement une fois. Si vous oubliez de définir quelque chose qui a été déclaré et référencé quelque part, alors l'éditeur de liens ne sait pas à quoi lier les références et se plaint d'un symbole manquant. Si vous définissez quelque chose plusieurs fois, l'éditeur de liens ne sait pas à laquelle des définitions lier les références et se plaint des symboles dupliqués.
Étant donné que le débat sur ce qu'est une déclaration de classe par rapport à une définition de classe en C ++ revient constamment (dans les réponses et les commentaires à d'autres questions), je vais coller ici une citation de la norme C ++.
En 3.1 / 2, C ++ 03 dit:
Une déclaration est une définition, sauf [...] s'il s'agit d'une déclaration de nom de classe [...].
3.1 / 3 donne ensuite quelques exemples. Parmi eux:
[Exemple: [...] struct S {int a; int b; }; // définit S, S :: a et S :: b [...] struct S; // déclare S —Fin exemple
Pour résumer: Le standard C ++ considère struct x;
être une déclaration et struct x {};
une définition . (En d'autres termes, «déclaration directe» est un terme impropre , car il n'y a pas d'autres formes de déclarations de classe en C ++.)
Merci à litb (Johannes Schaub) qui a creusé le chapitre et le verset dans l'une de ses réponses.
extern int i
est une déclaration, car elle introduit / spécifie simplement i
. Vous pouvez en avoir autant extern int i
que vous le souhaitez dans chaque unité de compilation. int i
, cependant, est une définition. Il indique l'espace pour l'entier dans cette unité de traduction et conseille à l'éditeur de liens de lier toutes les références à i
cette entité. Si vous avez plus ou moins qu'une de ces définitions, l'éditeur de liens se plaindra.
int i;
dans le fichier / la portée globale ou la portée de la fonction est une définition à la fois en C et C ++. En C car il alloue du stockage, et en C ++ car il n'a pas le spécificateur externe ou une spécification de liaison. Celles-ci reviennent à la même chose, ce que dit sbi: dans les deux cas, cette déclaration spécifie l'objet auquel toutes les références à "i" dans cette portée doivent être liées.
struct A { double f(int, double); double f(int, double); };
invalide, bien sûr. C'est autorisé ailleurs cependant. Il y a quelques endroits où vous pouvez déclarer des choses, mais pas définir aussi: void f() { void g(); }
valide, mais pas ce qui suit: void f() { void g() { } };
. Qu'est-ce qu'une définition et quelle déclaration a des règles subtiles en ce qui concerne les modèles - méfiez-vous! +1 pour une bonne réponse cependant.
De la section standard C ++ 3.1:
Une déclaration introduit des noms dans une unité de traduction ou redéclare des noms introduits par des déclarations précédentes. Une déclaration précise l'interprétation et les attributs de ces noms.
Le paragraphe suivant déclare (je souligne) qu'une déclaration est une définition à moins que ...
... il déclare une fonction sans spécifier le corps de la fonction:
void sqrt(double); // declares sqrt
... il déclare un membre statique dans une définition de classe:
struct X
{
int a; // defines a
static int b; // declares b
};
... il déclare un nom de classe:
class Y;
... il contient le extern
mot - clé sans initialiseur ni corps de fonction:
extern const int i = 0; // defines i
extern int j; // declares j
extern "C"
{
void foo(); // declares foo
}
... ou est une instruction typedef
or using
.
typedef long LONG_32; // declares LONG_32
using namespace std; // declares std
Maintenant, pour la grande raison pour laquelle il est important de comprendre la différence entre une déclaration et une définition: la règle d'une définition . De la section 3.2.1 de la norme C ++:
Aucune unité de traduction ne doit contenir plus d'une définition d'une variable, d'une fonction, d'un type de classe, d'un type d'énumération ou d'un modèle.
struct x {static int b = 3; };
?
b
est également déclarée const
. Voir stackoverflow.com/a/3536513/1858225 et daniweb.com/software-development/cpp/threads/140739/… .
Déclaration: "Quelque part, il existe un foo."
Définition: "... et le voici!"
Il existe des cas de bord intéressants en C ++ (certains d'entre eux en C aussi). Considérer
T t;
Cela peut être une définition ou une déclaration, selon le type T
:
typedef void T();
T t; // declaration of function "t"
struct X {
T t; // declaration of function "t".
};
typedef int T;
T t; // definition of object "t".
En C ++, lors de l'utilisation de modèles, il existe un autre cas de bord.
template <typename T>
struct X {
static int member; // declaration
};
template<typename T>
int X<T>::member; // definition
template<>
int X<bool>::member; // declaration!
La dernière déclaration n'était pas une définition. C'est la déclaration d'une spécialisation explicite du membre statique de X<bool>
. Il indique au compilateur: "S'il s'agit d'instancier X<bool>::member
, alors n'instanciez pas la définition du membre à partir du modèle principal, mais utilisez la définition trouvée ailleurs". Pour en faire une définition, vous devez fournir un initialiseur
template<>
int X<bool>::member = 1; // definition, belongs into a .cpp file.
Déclaration
Les déclarations indiquent au compilateur qu'il existe un élément ou un nom de programme. Une déclaration introduit un ou plusieurs noms dans un programme. Les déclarations peuvent se produire plusieurs fois dans un programme. Par conséquent, des classes, des structures, des types énumérés et d'autres types définis par l'utilisateur peuvent être déclarés pour chaque unité de compilation.
Définition
Les définitions spécifient le code ou les données que le nom décrit. Un nom doit être déclaré avant de pouvoir être utilisé.
class foo {};
c'est une définition de classe , n'est-ce pas?
D'après la norme C99, 6.7 (5):
Une déclaration spécifie l'interprétation et les attributs d'un ensemble d'identifiants. Une définition d'un identifiant est une déclaration pour cet identifiant qui:
De la norme C ++, 3.1 (2):
Une déclaration est une définition sauf si elle déclare une fonction sans spécifier le corps de la fonction, elle contient le spécificateur externe ou une spécification de liaison et ni un initialiseur ni un corps de fonction, elle déclare un membre de données statiques dans une déclaration de classe, c'est un déclaration de nom de classe, ou c'est une déclaration typedef, une déclaration using ou une directive using.
Ensuite, il y a quelques exemples.
Il est donc intéressant (ou non, mais je suis légèrement surpris), typedef int myint;
une définition en C99, mais seulement une déclaration en C ++.
typedef
, cela ne signifierait-il pas qu'il pourrait être répété en C ++, mais pas en C99?
De wiki.answers.com:
Le terme déclaration signifie (en C) que vous indiquez au compilateur le type, la taille et en cas de déclaration de fonction, le type et la taille de ses paramètres de n'importe quelle variable, ou le type ou la fonction défini par l'utilisateur dans votre programme. Aucun espace n'est réservé en mémoire pour aucune variable en cas de déclaration. Cependant, le compilateur sait combien d'espace à réserver en cas de création d'une variable de ce type.
par exemple, voici toutes les déclarations:
extern int a;
struct _tagExample { int a; int b; };
int myFunc (int a, int b);
La définition, d'autre part, signifie qu'en plus de tout ce que fait la déclaration, l'espace est également réservé en mémoire. Vous pouvez dire "DÉFINITION = DÉCLARATION + RÉSERVATION D'ESPACE" ci-dessous sont des exemples de définition:
int a;
int b = 0;
int myFunc (int a, int b) { return a + b; }
struct _tagExample example;
voir Réponses .
struct foo {};
c'est une définition , pas une déclaration. Une déclaration de foo
serait struct foo;
. De là, le compilateur ne sait pas combien d'espace à réserver pour les foo
objets.
struct foo;
est une déclaration, mais elle n'indique pas au compilateur la taille de foo. J'ajouterais que struct _tagExample { int a; int b; };
c'est une définition. Dans ce contexte, il est donc trompeur d'appeler cela une déclaration. Bien sûr, c'est un, car toutes les définitions sont des déclarations, mais vous semblez suggérer que ce n'est pas une définition. C'est une définition de _tagExample.
Puisque je ne vois pas de réponse pertinente pour C ++ 11, en voici une.
Une déclaration est une définition à moins qu'elle ne déclare un / n:
enum X : int;
template<typename T> class MyArray;
int add(int x, int y);
using IntVector = std::vector<int>;
static_assert(sizeof(int) == 4, "Yikes!")
;
Clauses supplémentaires héritées de C ++ 03 par la liste ci-dessus:
int add(int x, int y);
extern int a;
ouextern "C" { ... };
class C { static int x; };
struct Point;
typedef int Int;
using std::cout;
using namespace NS;
Une déclaration-modèle est une déclaration. Une déclaration de modèle est également une définition si sa déclaration définit une fonction, une classe ou un membre de données statique.
Exemples de la norme qui différencie la déclaration et la définition que j'ai trouvé utiles pour comprendre les nuances entre eux:
// except one all these are definitions
int a; // defines a
extern const int c = 1; // defines c
int f(int x) { return x + a; } // defines f and defines x
struct S { int a; int b; }; // defines S, S::a, and S::b
struct X { // defines X
int x; // defines non-static data member x
static int y; // DECLARES static data member y
X(): x(0) { } // defines a constructor of X
};
int X::y = 1; // defines X::y
enum { up , down }; // defines up and down
namespace N { int d; } // defines N and N::d
namespace N1 = N; // defines N1
X anX; // defines anX
// all these are declarations
extern int a; // declares a
extern const int c; // declares c
int f(int); // declares f
struct S; // declares S
typedef int Int; // declares Int
extern X anotherX; // declares anotherX
using N::d; // declares N::d
// specific to C++11 - these are not from the standard
enum X : int; // declares X with int as the underlying type
using IntVector = std::vector<int>; // declares IntVector as an alias to std::vector<int>
static_assert(X::y == 1, "Oops!"); // declares a static_assert which can render the program ill-formed or have no effect like an empty declaration, depending on the result of expr
template <class T> class C; // declares template class C
; // declares nothing
Définition:
extern int a; // Declaration
int a; // Definition
a = 10 // Initialization
int b = 10; // Definition & Initialization
La définition associe la variable à un type et alloue de la mémoire, tandis que la déclaration spécifie simplement le type mais n'alloue pas de mémoire. La déclaration est plus utile lorsque vous souhaitez référencer la variable avant la définition.
* Ne confondez pas définition et initialisation. Les deux sont différents, l'initialisation donne de la valeur à la variable. Voir l'exemple ci-dessus.
Voici quelques exemples de définition.
int a;
float b;
double c;
Maintenant , déclaration de fonction:
int fun(int a,int b);
Notez le point-virgule à la fin de la fonction, il indique donc que ce n'est qu'une déclaration. Le compilateur sait que quelque part dans le programme, cette fonction sera définie avec ce prototype. Maintenant, si le compilateur obtient un appel de fonction quelque chose comme ça
int b=fun(x,y,z);
Le compilateur générera une erreur indiquant qu'il n'y a pas une telle fonction. Parce qu'il n'a pas de prototype pour cette fonction.
Notez la différence entre deux programmes.
Programme 1
#include <stdio.h>
void print(int a)
{
printf("%d",a);
}
main()
{
print(5);
}
En cela, la fonction d'impression est également déclarée et définie. Puisque l'appel de fonction vient après la définition. Maintenant, voyez le programme suivant.
Programme 2
#include <stdio.h>
void print(int a); // In this case this is essential
main()
{
print(5);
}
void print(int a)
{
printf("%d",a);
}
Il est essentiel car l'appel de fonction précède la définition, le compilateur doit donc savoir s'il existe une telle fonction. Nous déclarons donc la fonction qui informera le compilateur.
Définition:
Cette partie de la définition d'une fonction est appelée Définition. Il indique quoi faire à l'intérieur de la fonction.
void print(int a)
{
printf("%d",a);
}
int a; //declaration; a=10; //definition
C'est complètement faux. Lorsque l'on parle d'objets de durée de stockage automatique (objets déclarés dans une définition de fonction qui ne sont pas déclarés avec un autre spécificateur de classe de stockage comme extern), ce sont toujours des définitions.
la définition signifie la fonction réelle écrite et la déclaration signifie une simple fonction de déclaration pour par exemple
void myfunction(); //this is simple declaration
et
void myfunction()
{
some statement;
}
c'est la définition de la fonction myfunction
Règle générale:
Une déclaration indique au compilateur comment interpréter les données de la variable en mémoire. Ceci est nécessaire pour chaque accès.
Une définition réserve la mémoire pour rendre la variable existante. Cela doit se produire exactement une fois avant le premier accès.
Pour comprendre les noms, concentrons-nous d'abord sur les verbes.
déclarer - annoncer officiellement; proclamer
définir - montrer ou décrire (quelqu'un ou quelque chose) clairement et complètement
Ainsi, lorsque vous déclarez quelque chose, vous dites simplement ce que c'est .
// declaration
int sum(int, int);
Cette ligne déclare une fonction C appelée sum
qui prend deux arguments de type int
et retourne un int
. Cependant, vous ne pouvez pas encore l'utiliser.
Lorsque vous indiquez comment cela fonctionne réellement , c'est sa définition.
// definition
int sum(int x, int y)
{
return x + y;
}
Pour comprendre la différence entre déclaration et définition, nous devons voir le code assembleur:
uint8_t ui8 = 5; | movb $0x5,-0x45(%rbp)
int i = 5; | movl $0x5,-0x3c(%rbp)
uint32_t ui32 = 5; | movl $0x5,-0x38(%rbp)
uint64_t ui64 = 5; | movq $0x5,-0x10(%rbp)
double doub = 5; | movsd 0x328(%rip),%xmm0 # 0x400a20
movsd %xmm0,-0x8(%rbp)
et ce n'est qu'une définition:
ui8 = 5; | movb $0x5,-0x45(%rbp)
i = 5; | movl $0x5,-0x3c(%rbp)
ui32 = 5; | movl $0x5,-0x38(%rbp)
ui64 = 5; | movq $0x5,-0x10(%rbp)
doub = 5; | movsd 0x328(%rip),%xmm0 # 0x400a20
movsd %xmm0,-0x8(%rbp)
Comme vous pouvez le voir, rien ne change.
La déclaration est différente de la définition car elle donne des informations utilisées uniquement par le compilateur. Par exemple, uint8_t indique au compilateur d'utiliser la fonction asm movb.
Regarde ça:
uint def; | no instructions
printf("some stuff..."); | [...] callq 0x400450 <printf@plt>
def=5; | movb $0x5,-0x45(%rbp)
La déclaration n'a pas d'instruction équivalente car il n'y a rien à exécuter.
De plus, la déclaration indique au compilateur la portée de la variable.
Nous pouvons dire que la déclaration est une information utilisée par le compilateur pour établir l'utilisation correcte de la variable et pour combien de temps une mémoire appartient à une certaine variable.
Ne pourriez-vous pas dire dans les termes les plus généraux possibles, qu'une déclaration est un identifiant dans lequel aucun stockage n'est alloué et qu'une définition alloue réellement du stockage à partir d'un identifiant déclaré?
Une pensée intéressante - un modèle ne peut pas allouer de stockage tant que la classe ou la fonction n'est pas liée aux informations de type. L'identifiant du modèle est-il donc une déclaration ou une définition? Il doit s'agir d'une déclaration car aucun stockage n'est alloué et vous êtes simplement en train de «prototyper» la classe ou la fonction de modèle.
template<class T> struct foo;
s'agit d'une déclaration de modèle , tout comme celle-ci template<class T> void f();
. Les définitions de modèle reflètent les définitions de classe / fonction de la même manière. (Notez qu'un nom de modèle n'est pas un type ou un nom de fonction . Un endroit où vous pouvez le voir est lorsque vous ne pouvez pas passer un modèle en tant que paramètre de type d'un autre modèle. Si vous souhaitez transmettre des modèles au lieu de types, vous avez besoin de paramètres de modèle de modèle. )
Trouvez des réponses similaires ici: Questions techniques d'entretien en C .
Une déclaration donne un nom au programme; une définition fournit une description unique d'une entité (par exemple, type, instance et fonction) dans le programme. Les déclarations peuvent être répétées dans une étendue donnée, elle introduit un nom dans une étendue donnée.
Une déclaration est une définition sauf si:
Une définition est une déclaration sauf si:
Cela va sembler vraiment ringard, mais c'est la meilleure façon dont j'ai pu garder les termes droits dans ma tête:
Déclaration: Photo Thomas Jefferson prononçant un discours ... "JE DÉCLARE PAR LA PRÉSENTE QUE CE FOO EXISTE DANS CE CODE SOURCE !!!"
Définition: imaginez un dictionnaire, vous recherchez Foo et ce que cela signifie réellement.
Selon le manuel de la bibliothèque GNU C ( http://www.gnu.org/software/libc/manual/html_node/Header-Files.html )
En C, une déclaration fournit simplement des informations sur l'existence d'une fonction ou d'une variable et donne son type. Pour une déclaration de fonction, des informations sur les types de ses arguments peuvent également être fournies. Le but des déclarations est de permettre au compilateur de traiter correctement les références aux variables et fonctions déclarées. En revanche, une définition alloue en fait du stockage à une variable ou indique ce qu'une fonction fait.
Le concept de Déclaration et Définition formera un écueil lorsque vous utilisez la classe de stockage externe car votre définition se trouvera dans un autre emplacement et vous déclarez la variable dans votre fichier de code local (page). Une différence entre C et C ++ est qu'en C vous les déclarations se font normalement au début d'une fonction ou d'une page de code. En C ++, ce n'est pas comme ça. Vous pouvez déclarer au lieu de votre choix.
Mon exemple préféré est "int Num = 5" ici votre variable est 1. définie comme int 2. déclarée comme Num et 3. instanciée avec une valeur de cinq. nous
Une classe ou une structure vous permet de modifier la façon dont les objets seront définis lors de leur utilisation ultérieure. Par exemple
Lorsque nous apprenons à programmer, ces deux termes sont souvent confondus, car nous faisons souvent les deux en même temps.
Étapes d'une génération exécutable:
(1) pré-processeur -> (2) traducteur / compilateur -> (3) éditeur de liens
Dans l'étape 2 (traducteur / compilateur), les instructions de déclaration dans notre code indiquent au compilateur que ces choses que nous allons utiliser à l'avenir et vous pouvez trouver la définition plus tard, ce qui signifie:
traducteur assurez-vous que: qu'est-ce que quoi? signifie déclaration
et (3) l'étape (l'éditeur de liens) a besoin d'une définition pour lier les choses
Linker assurez-vous que: où est quoi? signifie définition
Il y a des définitions très claires parsemées dans K&R (2e édition); il est utile de les mettre au même endroit et de les lire comme un seul:
"Définition" fait référence à l'endroit où la variable est créée ou affectée au stockage; "déclaration" fait référence aux endroits où la nature de la variable est indiquée mais aucun stockage n'est alloué. [p. 33]
...
Il est important de faire la distinction entre la déclaration d'une variable externe et sa définition . Une déclaration annonce les propriétés d'une variable (principalement son type); une définition entraîne également l'annulation du stockage. Si les lignes
int sp; double val[MAXVAL]
apparaissent en dehors de toute fonction, ils définissent les variables externes
sp
etval
entraînent la mise de côté du stockage et servent également de déclaration pour le reste de ce fichier source.En revanche, les lignes
extern int sp; extern double val[];
déclarer pour le reste du fichier source qui
sp
est unint
et quival
est undouble
tableau (dont la taille est déterminée ailleurs), mais ils ne créent pas les variables ni ne leur réservent de stockage.Il ne doit y avoir qu'une seule définition d'une variable externe parmi tous les fichiers qui composent le programme source. ... Les tailles de tableau doivent être spécifiées avec la définition, mais sont facultatives avec un
extern
déclaration. [pp. 80-81]...
Les déclarations précisent l'interprétation donnée à chaque identifiant; ils ne réservent pas nécessairement le stockage associé à l'identifiant. Les déclarations qui réservent du stockage sont appelées définitions . [p. 210]
La déclaration signifie donner un nom et un type à une variable (en cas de déclaration de variable), par exemple:
int i;
ou donner le nom, le type de retour et le type de paramètre (s) à une fonction sans corps (en cas de déclaration de fonction), par exemple:
int max(int, int);
tandis que la définition signifie attribuer une valeur à une variable (en cas de définition de variable), par exemple:
i = 20;
ou fournir / ajouter un corps (fonctionnalité) à une fonction est appelé définition de fonction, par exemple:
int max(int a, int b)
{
if(a>b) return a;
return b;
}
plusieurs déclarations de temps et définition peuvent être faites ensemble comme:
int i=20;
et:
int max(int a, int b)
{
if(a>b) return a;
return b;
}
Dans les cas ci-dessus, nous définissons et déclarons les variables i
et function max()
.
int x;