c - sur - taguer




Quelle est la différence entre une définition et une déclaration? (17)

Mise à jour C ++ 11

Puisque je ne vois pas de réponse pertinente à C ++ 11, en voici une.

Une déclaration est une définition sauf si elle déclare un / n:

  • opaque enum - enum X : int;
  • paramètre template - T dans le template<typename T> class MyArray;
  • déclaration de paramètres - x et y dans int add(int x, int y);
  • déclaration d'alias - en using IntVector = std::vector<int>;
  • déclaration d' static_assert(sizeof(int) == 4, "Yikes!") statique - static_assert(sizeof(int) == 4, "Yikes!")
  • déclaration d'attribut (définie par l'implémentation)
  • déclaration vide ;

Clauses supplémentaires héritées de C ++ 03 par la liste ci-dessus:

  • déclaration de fonction - ajouter int add(int x, int y);
  • spécificateur externe contenant une déclaration ou un spécificateur de liaison - extern int a; ou extern "C" { ... };
  • membre de données statiques dans une classe - x dans la class C { static int x; }; class C { static int x; };
  • classe / struct declaration - struct Point;
  • déclaration typedef - typedef int Int;
  • en utilisant la déclaration - en using std::cout;
  • using directive - using namespace NS;

Une déclaration de 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 statiques.

Exemples de la norme qui différencie la déclaration et la définition que j'ai trouvé utile 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

Le sens des deux m'échappe.


Cela va sembler vraiment ringard, mais c'est la meilleure façon dont j'ai pu garder les termes dans ma tête:

Déclaration: Picture Thomas Jefferson prononçant un discours ... "JE DÉCLARE PAR LA PRÉSENTE QUE CETTE FOO EXISTE DANS CE CODE SOURCE !!!"

Définition: image un dictionnaire, vous cherchez Foo et ce que cela signifie réellement.


De 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:

  • pour un objet, le stockage est réservé à cet objet;
  • pour une fonction, inclut le corps de la fonction;
  • pour une constante d'énumération ou un nom typedef, est la déclaration (seulement) de l'identifiant.

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 extern 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 il s'agit d'une déclaration typedef, d'une déclaration d'utilisation ou d'une directive using.

Ensuite, il y a quelques exemples.

Donc intéressant (ou pas, mais je suis un peu surpris), typedef int myint; est une définition en C99, mais seulement une déclaration en C ++.


De la section standard C ++ 3.1:

Une déclaration introduit les noms dans une unité de traduction ou réaffirme les noms introduits par les déclarations précédentes. Une déclaration spécifie l'interprétation et les attributs de ces noms.

Le paragraphe suivant déclare (soulignement le mien) 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 mot-clé extern sans un initialiseur ou un corps de fonction

extern const int i = 0;  // defines i
extern int j;  // declares j
extern "C"
{
    void foo();  // declares foo
}

... ou est un typedef ou une instruction using .

typedef long LONG_32;  // declares LONG_32
using namespace std;   // declares std

Maintenant, pour la grande raison pourquoi il est important de comprendre la différence entre une déclaration et une définition: la règle de définition unique . De la section 3.2.1 de la norme C ++:

Aucune unité de traduction ne doit contenir plus d'une définition de variable, de fonction, de type de classe, de type d'énumération ou de modèle.


Différence entre déclarer et définir avec des fonctions: L'instruction prototype d'une fonction la déclare, c'est-à-dire indique au compilateur la fonction - son nom, son type de retour, et le nombre et le type de ses paramètres. L'en-tête de la fonction, suivi du corps de la fonction, définit la fonction - donnant les détails des étapes pour effectuer l'opération de la fonction.

Ex.

Code:

//Declare
int foo(int);

//Define
int foo(int){
...
}

En ce qui concerne les variables: Pour les variables automatiques et de registre, il n'y a pas de différence entre la définition et la déclaration. Le processus de déclaration d'une variable automatique ou registre définit le nom de la variable et alloue la mémoire appropriée.

Cependant, pour les variables externes: Parce que la mémoire d'une variable ne doit être allouée qu'une seule fois, pour s'assurer que l'accès à la variable se réfère toujours à la même cellule. toutes les variables doivent être définies une fois et une seule fois.

Si une variable externe doit être utilisée dans un fichier autre que celui dans lequel elle est définie, un mécanisme est nécessaire pour "connecter" une telle utilisation avec la cellule de variable externe définie de manière unique qui lui est allouée. Ce processus de connexion des références de la même variable externe dans différents fichiers est appelé résolution des références.

Il peut être défini et déclaré avec une déclaration en dehors de toute fonction, sans spécificateur de classe de stockage. Une telle déclaration alloue de la mémoire pour la variable. Une déclaration de déclaration peut également être utilisée pour déclarer simplement un nom de variable avec le spécificateur de classe de stockage externe au début de la déclaration. Une telle déclaration spécifie que la variable est définie ailleurs, c'est-à-dire que la mémoire de cette variable est allouée dans un autre fichier. Ainsi, l'accès à une variable externe dans un fichier autre que celui dans lequel elle est définie est possible si elle est déclarée avec le mot-clé extern; aucune nouvelle mémoire n'est allouée. Une telle déclaration indique au compilateur que la variable est définie ailleurs et que le code est compilé avec la variable externe non résolue. La référence à la variable externe est résolue pendant le processus de liaison.

Ex.

Code

//file1.c
extern char stack[10];
extern int stkptr;
....

//file2.c
char stack[10];
int stkptr;
....

Ces déclarations indiquent au compilateur que les variables stack [] et stkptr sont définies ailleurs, généralement dans un autre fichier. Si le mot-clé extern était omis, les variables seraient considérées comme nouvelles et la mémoire leur serait allouée. Rappelez-vous que l'accès à la même variable externe définie dans un autre fichier n'est possible que si le mot-clé extern est utilisé dans la déclaration.


Il y a des cas 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 bordure.

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 , n'instanciez pas la définition du membre du template primaire, 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.

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 une définition alloue réellement le stockage à partir d'un identificateur déclaré?

Une idée intéressante: un modèle ne peut pas allouer de stockage tant que la classe ou la fonction n'est pas liée à l'information de type. L'identificateur de gabarit est-il une déclaration ou une définition? Cela devrait être une déclaration car aucun stockage n'est alloué, et vous ne faites que «prototyper» la classe ou la fonction du modèle.


Pour comprendre la différence entre la déclaration et la définition, nous devons voir le code d'assemblage:

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 ceci est seulement la 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 fournit des informations utilisées uniquement par le compilateur. Par exemple, uint8_t dit au compilateur d'utiliser la fonction asm movb.

Regarde ça:

uint def;                  |  no instructions
printf("some stuff...");   |  [...] callq   0x400450 <[email protected]>
def=5;                     |  movb    $0x5,-0x45(%rbp)

La déclaration n'a pas d'instruction équivalente car ce n'est pas quelque chose à exécuter.

De plus, declaration indique au compilateur la portée de la variable.

Nous pouvons dire que declaration 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 à certaine variable.


Règle de base:

  • 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.


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 l'information qu'une fonction ou variable existe 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. Une définition, en revanche, alloue réellement le stockage pour une variable ou dit ce qu'une fonction fait.


Une déclaration introduit un identifiant et décrit son type, qu'il s'agisse d'un type, d'un objet ou d'une fonction. Une déclaration est ce que le compilateur doit 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 cet identifiant. C'est ce dont le linker a besoin pour lier les 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, l'éditeur de liens ne sait pas à quoi associer les références et se plaint d'un symbole manquant. Si vous définissez quelque chose plus d'une fois, l'éditeur de liens ne sait pas laquelle des définitions lier des références et se plaint des symboles dupliqués.

Depuis le débat, ce qui est une déclaration de classe par rapport à une définition de classe en C ++ revient (dans les réponses et les commentaires à d'autres questions), je vais coller une citation de la norme C ++ ici.
A 3.1 / 2, C ++ 03 dit:

Une déclaration est une définition à moins qu'elle [...] ne soit une déclaration de nom de classe [...].

3.1 / 3 donne ensuite quelques exemples. Parmi eux:

[Example: [...]
struct S { int a; int b; }; // defines S, S::a, and S::b [...]
struct S; // declares S
—end example

Pour résumer: Le standard C ++ considère struct x; être une déclaration et struct x {}; une définition . (En d'autres termes, "forward statement" est un terme inapproprié 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 une de ses réponses.


Une déclaration introduit un nom dans le programme; une définition fournit une description unique d'une entité (par exemple, type, instance et fonction). Les déclarations peuvent être répétées dans une portée donnée, elle introduit un nom dans une portée donnée. Il doit y avoir exactement une définition de chaque objet, fonction ou classe utilisée dans un programme C ++. Une déclaration est une définition sauf si:

* it declares a function without specifying its body,
* it contains an extern specifier and no initializer or function body,
* it is the declaration of a static class data member without a class definition,
* it is a class name definition,
* it is a typedef declaration.

Une définition est une déclaration sauf:

* it defines a static class data member,
* it defines a non-inline member function.

Déclaration:

int a; // this declares the variable 'a' which is of type 'int'

Ainsi, la déclaration associe la variable à un type.

Voici quelques exemples de déclaration.

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 afin qu'il indique que c'est seulement 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 une fonction appelez quelque chose comme ça

int b=fun(x,y,z);

Le compilateur va lancer une erreur en disant qu'il n'y a pas de 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);
}

Dans ce cas, la fonction d'impression est également déclarée et définie. Puisque l'appel de fonction arrive après la définition. Maintenant, voir le prochain programme.

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 à la fonction précède la définition, de sorte que le compilateur doit savoir s'il existe une telle fonction. Nous déclarons donc la fonction qui va informer le compilateur.

Définition

Cette partie de la définition d'une fonction s'appelle Définition. Il dit quoi faire à l'intérieur de la fonction.

void print(int a)
{
    printf("%d",a);
}

Maintenant avec les variables.

int a; //declaration
a=10; //definition 

Parfois, la déclaration et la définition sont regroupées dans une seule déclaration comme celle-ci.

int a=10;

Déclaration

Les déclarations indiquent au compilateur qu'un élément de programme ou un nom existe. Une déclaration introduit un ou plusieurs noms dans un programme. Les déclarations peuvent se produire plus d'une 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é.


A variable is declared when the compiler is informed that a variable exists (and this is its type); it does not allocate the storage for the variable at that point.

A variable is defined when the compiler allocates the storage for the variable.


My favorite example is "int Num = 5" here your variable is 1. defined as int 2. declared as Num and 3. instantiated with a value of five. We

  • Define the type of an object, which may be built-in or a class or struct.
  • Declare the name of an object, so anything with a name has been declared which includes Variables, Funtions, etc.

A class or struct allows you to change how objects will be defined when it is later used. Par exemple

  • One may declare a heterogeneous variable or array which are not specifically defined.
  • Using an offset in C++ you may define an object which does not have a declared name.

When we learn programming these two terms are often confused because we often do both at the same time.


Whenever we write function after the main function, compiler will through the error since it does not have any idea about the function at the time of calling function. If we provide prototype declaration of function then we compiler will not look for the definition.

int sum(int,int);

main()
{
    int res = sum(10,20);
}
int sum(int n1,int n2)
{
    return(n1+n2);
}

In the above example , first line is called as function declaration.

int sum(int,int);

Declaring Variable

Whenever we write declaration statement then memory will not be allocated for the variable. Variable declaration will randomly specify the memory location.

int ivar;
float fvar;

Variable Declaration Vs Definition Differentiation Parameters

A. Space Reservation :

Whenever we declare a variable then space will not be reserved for the variable. Whenever we declare a variable then compiler will not look for other details such as definition of the variable.

La déclaration est un moyen pratique d'écrire du code dans lequel la mémoire réelle n'est pas allouée.

struct book  {
    int pages;
    float price;
    char *bname;
};

Dans la déclaration ci-dessus, la mémoire n'est pas allouée. Chaque fois que nous définissons une variable, la mémoire sera allouée à la variable.

struct book b1;

B. Qu'est-ce que ça fait?

  1. La déclaration identifiera le type de données de l'identifiant.
  2. La définition de la variable lui attribuera une certaine valeur.






c++-faq