关于C#:定义和声明有什么区别?

What is the difference between a definition and a declaration?

我不明白这两者的意思。


本文介绍了A,文件标识符和其它类型的A型,对象,或功能。a宣言是"引用,编译器需要接受标识符。这些声明:

1
2
3
4
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

这是实现A /实例化定义的标识符。我需要它是为了连接这些链接引用的实体。这是一个定义相应的上述声明:

1
2
3
4
int bar;
int g(int lhs, int rhs) {return lhs*rhs;}
double f(int i, double d) {return i+d;}
class foo {};

a的定义可以用在地方的一对。

标识符可以被作为经常你想。因此,下面的是合法的在C和C + +。

1
2
3
4
double f(int, double);
double f(int, double);
extern double f(int, double); // the same as the two above
extern double f(int, double);

然而,它也必须定义一次。如果你忘了一个东西已经被定义和引用的地方,然后在不知道链接到链接引用是一个符号和失踪的投诉。如果你使用更多的东西比一次的话,不知道链接的链接定义一个符号引用复制和投诉。

自从辩论什么是A A类声明和类定义在C + +(在一,回答和评论的其他问题),我会贴在A比C + +的标准在这里。在1 / 2,C++ 03说:

A declaration is a definition unless it [...] is a class name declaration [...].

3.1/3然后给一些例子。::他们

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

和它的一个C + +标准认为:struct x;宣言和一个struct x {};定义。(换句话说,"前锋A misnomer宣言",因为没有其他窗体类的声明在C + +)。

感谢litb(Johannes Schaub)谁挖出的实际和诗一章他的答案。


从C + +标准第3.1:

A declaration introduces names into a translation unit or redeclares names introduced by previous
declarations. A declaration specifies the interpretation and attributes of these names.

一条新世(重点矿山)是一个明确的定义,除非……

……它declares没有指定函数的函数体

1
void sqrt(double);  // declares sqrt

……它declares a在一类定义的静态成员

1
2
3
4
5
struct X
{
    int a;         // defines a
    static int b;  // declares b
};

……它declares a类名称

1
class Y;

……它包含的关键字或extern没有初始化函数体

1
2
3
4
5
6
extern const int i = 0;  // defines i
extern int j;  // declares j
extern"C"
{
    void foo();  // declares foo
}

……或是一个typedefusing语句。

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

现在的大原因,为什么它的重要知道差别在声明和定义:一定义规则。第3.2.1条和《C++标准:

No translation unit shall contain more than one definition of any variable, function, class type, enumeration type, or template.


声明:"在某个地方,存在一个foo。"

定义:"……就在这里!"


C++中有一些有趣的边缘情况(其中有些也在C中)。考虑

1
T t;

这可以是定义或声明,具体取决于T是什么类型:

1
2
3
4
5
6
7
8
9
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".

在C++中,当使用模板时,还有另一种边缘情况。

1
2
3
4
5
6
7
8
9
10
template <typename T>
struct X {
  static int member; // declaration
};

template<typename T>
int X<T>::member; // definition

template<>
int X<bool>::member; // declaration!

最后一个声明不是定义。这是对X静态成员明确专门化的声明。它告诉编译器:"如果要实例化X::member,那么不要从主模板实例化成员的定义,而是使用其他地方找到的定义。"要使其成为定义,必须提供初始值设定项

1
2
template<>
int X<bool>::member = 1; // definition, belongs into a .cpp file.


宣言

Declarations tell the compiler that a
program element or name exists. A
declaration introduces one or more
names into a program. Declarations can
occur more than once in a program.
Therefore, classes, structures,
enumerated types, and other
user-defined types can be declared for
each compilation unit.

定义

Definitions specify what code or data
the name describes. A name must be
declared before it can be used.


根据C99标准,6.7(5):

声明指定一组标识符的解释和属性。标识符的定义是该标识符的声明,该声明:

  • 对于一个对象,导致为该对象保留存储空间;
  • 对于功能,包括功能体;
  • 对于枚举常量或typedef名称,是标识符。

从C++标准,3.1(2):

声明是一个定义,除非它声明了一个没有指定函数体的函数,它包含外部说明符或链接规范,并且既不是初始值设定项也不是函数体,它声明了类声明中的静态数据成员,它是类名声明,或者它是typedef声明、using声明,或使用指令。

还有一些例子。

有趣的是(或者不是,但我有点吃惊),EDCOX1 0是C99中的一个定义,而只是C++中的一个声明。


从wiki.answers.com:

这项宣言的均值(C)你告诉编译器你的类型,大小和功能的情况下,文件大小,类型和它的参数的任何变量或函数,或用户定义的类型在你的计划。保留的内存空间是在没有任何变量的声明的情况下。然而,编译器知道多少空间,预定在这个变量的类型是实例的创建。

例如,下面的声明都是:

1
2
3
extern int a;
struct _tagExample { int a; int b; };
int myFunc (int a, int b);

在其他的手意味着定义中添加到所有的事情,所以这是对保留的内存空间中。你可以说"定义声明+空间=预订"的定义:以下是例子

1
2
3
4
int a;
int b = 0;
int myFunc (int a, int b) { return a + b; }
struct _tagExample example;

湖的答案。


C++ 11更新

因为我没有看到与C++ 11相关的答案,这里有一个。

声明是一个定义,除非声明了A/N:

  • 不透明枚举-enum X : int;
  • template class MyArray;中的模板参数-t
  • 参数声明-int add(int x, int y);中的x和y
  • 别名声明-using IntVector = std::vector;
  • 静态断言声明-static_assert(sizeof(int) == 4,"Yikes!")
  • 属性声明(已定义实现)
  • 空申报;

上面列表中从C++ 03继承的附加子句:

  • 功能声明-插件int add(int x, int y);
  • 包含声明或链接说明符的外部说明符-extern int a;extern"C" { ... };
  • class C { static int x; };中class-x中的静态数据成员
  • 类/结构声明-struct Point;
  • typedef声明-typedef int Int;
  • 使用声明-using std::cout;
  • 使用指令-using namespace NS;

模板声明是声明。如果模板声明定义函数、类或静态数据成员,则模板声明也是定义。

标准中区分声明和定义的示例有助于理解声明和定义之间的细微差别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 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

定义是指实际编写的函数,声明是指简单的声明函数例如

1
void  myfunction(); //this is simple declaration

1
2
3
4
void myfunction()
{
 some statement;    
}

这是函数myfunction的定义


经验法则:

  • 声明告诉编译器如何解释内存中变量的数据。每次访问都需要这样做。

  • 定义保留内存以使变量存在。这必须在第一次访问之前发生一次。


宣言:

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

因此,声明将变量与类型相关联。

下面是一些声明的例子。

1
2
3
int a;
float b;
double c;

现在函数声明:

1
int fun(int a,int b);

注意函数末尾的分号,它表示它只是一个声明。编译器知道程序中的某个地方将用该原型定义函数。现在,如果编译器得到一个函数,那么调用类似这样的函数

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

编译器将抛出一个错误,说明没有这样的函数。因为它没有这个函数的原型。

注意两个程序之间的区别。

程序1

1
2
3
4
5
6
7
8
9
#include <stdio.h>
void print(int a)
{
     printf("%d",a);
}
main()
{
    print(5);
}

在此,还声明和定义了print函数。因为函数调用在定义之后。现在看下一个节目。

程序2

1
2
3
4
5
6
7
8
9
10
 #include <stdio.h>
 void print(int a); // In this case this is essential
 main()
 {
    print(5);
 }
 void print(int a)
 {
     printf("%d",a);
 }

这是必要的,因为函数调用先于定义,所以编译器必须知道是否有这样的函数。所以我们声明一个函数,它将通知编译器。

定义:

定义函数的这一部分称为定义。它表示在函数内部要做什么。

1
2
3
4
void print(int a)
{
    printf("%d",a);
}

现在是变量。

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

有时,声明和定义被分组成这样的单个语句。

1
int a=10;


要了解声明和定义之间的区别,我们需要查看程序集代码:

1
2
3
4
5
6
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)

这是唯一的定义:

1
2
3
4
5
6
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)

你看不到任何变化。

声明不同于定义,因为它只提供编译器使用的信息。例如,uint8_t告诉编译器使用asm函数movb。

请参见:

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

声明没有等价的指令,因为它不是要执行的东西。

此外,声明还告诉编译器变量的作用域。

我们可以说,声明是编译器用来确定变量正确使用以及某些内存属于某个变量多长时间的信息。


为了理解名词,我们先把重点放在动词上。

声明-宣布正式宣布;宣布

定义-清楚、完整地展示或描述(某人或某物)

所以,当你申报一些东西时,你只需告诉它是什么。

1
2
// declaration
int sum(int, int);

此行声明一个名为sum的C函数,该函数接受int类型的两个参数,并返回int。但是,您还不能使用它。

当你提供它的实际工作方式时,这就是它的定义。

1
2
3
4
5
// definition
int sum(int x, int y)
{
    return x + y;
}

在这里找到类似的答案:C语言中的技术面试问题

声明为程序提供名称;定义为程序中的实体(例如类型、实例和函数)提供唯一的描述。声明可以在给定的作用域中重复,它在给定的作用域中引入一个名称。

声明是定义,除非

  • 声明声明声明了一个函数,但未指定其主体,
  • 声明包含外部说明符,没有初始值设定项或函数体,
  • 声明是没有类定义的静态类数据成员的声明,
  • 声明是类名定义,

定义是声明,除非:

  • 定义定义静态类数据成员,
  • 定义定义非内联成员函数。


您能否用最一般的术语表述,声明是一个没有分配存储的标识符,定义实际上从声明的标识符分配存储?

一个有趣的想法是,在类或函数与类型信息链接之前,模板无法分配存储空间。那么模板标识符是声明还是定义?它应该是一个声明,因为没有分配存储,而您只是"原型化"模板类或函数。


这听起来真的很俗气,但这是最好的方法,我能够保持我的头脑中的条款:

声明:图片托马斯·杰斐逊演讲…"我在此声明此foo存在于此源代码中!!

定义:想象一本字典,你正在查找foo及其实际含义。


声明向编译器提供符号名。定义是为符号分配空间的声明。

1
2
3
int f(int x); // function declaration (I know f exists)

int f(int x) { return 2*x; } // declaration and definition

根据GNU C库手册(http://www.gnu.org/software/libc/manual/html_node/header-files.html)

In C, a declaration merely provides information that a function or variable exists and gives its type. For a function declaration, information about the types of its arguments might be provided as well. The purpose of declarations is to allow the compiler to correctly process references to the declared variables and functions. A definition, on the other hand, actually allocates storage for a variable or says what a function does.


声明意味着给变量命名和类型(在变量声明的情况下)如:

1
 int i;

或者为没有主体的函数提供名称、返回类型和参数类型(在函数声明的情况下)

如:

1
int max(int, int);

而定义是指为变量赋值(在变量定义的情况下)。如:

1
i = 20;

或者为函数提供/添加主体(功能),称为函数定义。

如:

1
2
3
4
5
 int max(int a, int b)
 {
    if(a>b)   return a;
    return b;  
 }

许多时间声明和定义可以一起完成,如下所示:

1
int i=20;

1
2
3
4
5
int max(int a, int b)
{
    if(a>b)   return a;
    return b;    
}

在上述情况下,我们定义并声明变量i和函数max()。


可执行生成的阶段:

(1) pre-processor -> (2) translator/compiler -> (3) linker

在第2阶段(翻译器/编译器),我们代码中的声明语句告诉编译器我们将来要使用这些东西,您可以在后面找到定义,意思是:

translator make sure that : what is what ? means declaration

(3)阶段(链接器)需要定义来绑定事物

Linker make sure that : where is what ? means definition


当您使用外部存储类时,声明和定义的概念将形成一个陷阱,因为您的定义将在其他位置,并且您将在本地代码文件(第页)中声明变量。C和C++之间的一个区别是,在C中,声明通常在函数或代码页的起始处完成。在C++中不是这样的。你可以在你选择的地方申报。


我最喜欢的例子是"int num=5",这里您的变量是1。定义为int 2。声明为num和3。以5的值实例化。我们

  • 定义对象的类型,可以是内置的,也可以是类或结构。
  • 声明一个对象的名称,所以已经声明了任何具有名称的内容,其中包括变量、函数等。

类或结构允许您更改以后使用对象时如何定义对象。例如

  • 可以声明一个未被特别定义的异类变量或数组。
  • 在C++中使用偏移量,可以定义一个没有声明名称的对象。

当我们学习编程时,这两个术语经常混淆,因为我们经常同时做这两个术语。