定义和声明有什么区别?

What is the difference between a definition and a declaration?

提问人:Maciek 提问时间:9/11/2009 最后编辑:Jan SchultkeMaciek 更新时间:9/24/2023 访问量:463887

问:

我不明白两者的含义。

C C 声明 术语 C++-FAQ

评论

19赞 David Thornley 9/11/2009
坦率地说,我很难知道哪个是哪个,所以我没有发现这些名字很明显。我对含义没有问题,只是将哪些名称与含义相关联。
2赞 dmckee --- ex-moderator kitten 9/11/2009
我们已经详尽地讨论了这个问题:stackoverflow.com/questions/671925/......
1赞 Mooing Duck 6/27/2013
一个更有趣的问题是“声明和原型之间的区别”:stackoverflow.com/questions/5481579/......
1赞 Griffin 7/19/2013
这是一篇很好的文章,解释了 extern 关键字和内存分配如何与声明/定义相关: dreamincode.net/forums/topic/171468-declarations-vs-definitions
1赞 barlop 9/19/2015
这可能会有所帮助 cprogramming.com/declare_vs_define.html

答:

23赞 Marcin Gil 9/11/2009 #1

从 wiki.answers.com:

术语声明的意思是(在 C 中)您告诉编译器有关类型、大小的信息,如果是函数声明,则告诉编译器任何变量的参数的类型和大小,或者程序中用户定义的类型或函数。在声明的情况下,内存中不会为任何变量保留空间。但是,编译器知道在创建此类型的变量时要保留多少空间。

例如,以下是所有声明:

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

另一方面,定义意味着除了声明所做的所有事情之外,内存中还保留了空间。您可以说“DEFINITION = DECLARATION + SPACE RESERVATION”,以下是定义的示例:

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

请参阅答案

评论

3赞 sbi 9/11/2009
这也是错误的(尽管比其他的更接近):是一个定义,而不是一个声明。的声明是 。由此,编译器不知道要为对象保留多少空间。struct foo {};foostruct foo;foo
1赞 Steve Jessop 9/11/2009
@Marcin:SBI 说“编译器知道在创建这种类型的变量时要保留多少空间”并不总是正确的。 是一个声明,但它不会告诉编译器 foo 的大小。我要补充一点,这是一个定义。因此,在这种情况下,称其为声明是误导性的。当然,这是一个,因为所有定义都是声明,但你似乎在暗示它不是一个定义。这是对_tagExample的定义。struct foo;struct _tagExample { int a; int b; };
1赞 David Thornley 9/11/2009
@Marcin Gil:这意味着“答案”维基并不总是准确的。我必须在这里对错误信息投反对票。
1赞 Steve Jessop 9/11/2009
我们了解到adatapost引用的内容是真实的,但(IMO)并没有真正回答这个问题。Marcin引用的内容是错误的。引用标准是正确的,并回答了问题,但很难做出正面或反面。
1赞 sbi 9/11/2009
@onebyone:确实是一个非常好的总结!(然而,我强化了我作为学生所学到的东西,后来试图对我的学生进行锤击:不假思索地抄袭可能会导致灾难。:^>)
37赞 KV Prajapati 9/11/2009 #2

声明

声明告诉编译器 程序元素或名称存在。一个 声明介绍一个或多个 名称添加到程序中。声明可以 在一个程序中多次出现。 因此,类、结构、 枚举类型和其他 可以声明用户定义的类型 每个编译单元。

定义

定义指定哪些代码或数据 顾名思义。名称必须是 声明后才能使用。

评论

0赞 sbi 9/11/2009
嗯,难道你甚至可以在每个编译单元中定义类和枚举吗?至少我把类定义放到我的标题中,并将它们全部包含。呃,定义,不是吗?class foo {};
1赞 David Thornley 9/11/2009
是的。但是,“class foo;”是一个声明。它告诉编译器 foo 是一个类。 “class foo {};” 是一个定义。它准确地告诉编译器类 foo 是什么类型。
1赞 Johannes Schaub - litb 9/12/2009
例外情况是可以在声明之前使用的类成员名称。
1赞 Johannes Schaub - litb 9/12/2009
是的,这就是我的意思。因此,您可以执行以下操作: struct foo { void b() { f(); } void f(); }, f 是可见的,即使尚未声明。以下也有效: struct foo { void b(int = bar()); typedef int bar; };.它在“所有函数体、默认参数、构造函数 ctor-initializers”中的声明之前可见。不在返回类型:(中
1赞 sbi 9/12/2009
@litb:在声明之前不可见,只是标识符的使用被移到了声明后面。是的,我知道,在很多情况下效果是一样的。但并非适用于所有情况,这就是为什么我认为我们应该使用精确的解释。-- 哎呀,等等。它在默认参数中可见吗?好吧,这肯定会对我的理解造成严重破坏。该死的!<噘嘴>
1042赞 sbi 9/11/2009 #3

声明引入标识符并描述其类型,无论是类型、对象还是函数。声明是编译器接受对该标识符的引用所需的内容。这些是声明:

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

定义实际上实例化/实现此标识符。这是链接器将引用链接到这些实体所需的内容。这些是与上述声明相对应的定义:

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

可以使用定义来代替声明。

标识符可以根据需要随时声明。因此,以下内容在 C 和 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);

但是,它必须只定义一次。如果您忘记定义某处声明和引用的内容,则链接器不知道要链接引用的内容,并抱怨缺少符号。如果多次定义某些内容,则链接器不知道要将引用链接到哪个定义,并抱怨重复的符号。


由于 C++ 中的类声明与类定义是什么的争论不断出现(在其他问题的回答和评论中),我将在此处粘贴 C++ 标准的引用。
在 3.1/2 中,C++03 说:

声明是一个定义,除非它 [...] 是一个类名声明 [...]。

3.1/3 然后给出了几个例子。其中:

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

总结一下:C++ 标准被认为是一个声明和一个定义。(换句话说,“前向声明”用词不当,因为 C++ 中没有其他形式的类声明。struct x;struct x {};

感谢 litb (Johannes Schaub) 在他的一个答案中挖掘出实际的章节和经文。

评论

2赞 Steve Jessop 9/11/2009
@unknown:要么是你的编译器坏了,要么是你错误地复制了SBI的代码。例如,N1124中的6.7.2(2):“所有引用同一对象或函数的声明都应具有兼容的类型;否则,行为是未定义的。
4赞 David Thornley 9/11/2009
@Brian:“extern int i;”表示我是某处的 int,不用担心。“int i;” 表示 i 是 int,它的地址和作用域在这里确定。
14赞 sbi 9/11/2009
@Brian:你错了。 是一个声明,因为它只是引入/指定 .每个编译单元中可以有任意数量的编译单元。但是,这是一个定义。它表示整数在此转换单元中的空间,并建议链接器将所有引用链接到此实体。如果您拥有这些定义中的一个以上或少于一个,链接器将提出申诉。extern int iiextern int iint ii
5赞 Steve Jessop 9/11/2009
文件/全局作用域或函数作用域中的@Brian是 C 和 C++ 中的定义。在 C 中,因为它分配了存储,在 C++ 中,因为它没有 extern 说明符或链接规范。这些相当于同一件事,这就是 sbi 所说的:在这两种情况下,此声明都指定了该范围内所有对“i”的引用必须链接到的对象。int i;
5赞 Johannes Schaub - litb 9/12/2009
@unknown,请注意,您不能在范围内重新声明成员:当然是无效的。不过,在其他地方是允许的。在某些地方,您可以声明事物,但不能定义:有效,但不能定义以下内容:.当涉及到模板时,什么是定义和声明有微妙的规则 - 当心!+1 不过是一个很好的答案。struct A { double f(int, double); double f(int, double); };void f() { void g(); }void f() { void g() { } };
189赞 Michael Kristofik 9/11/2009 #4

来自 C++ 标准第 3.1 节:

声明将名称引入翻译单元或重新声明先前引入的名称 声明。声明指定这些名称的解释和属性。

下一段指出(强调我的)声明是一种定义,除非......

...它声明一个函数,而不指定函数的主体:

void sqrt(double);  // declares sqrt

...它在类定义中声明一个静态成员:

struct X
{
    int a;         // defines a
    static int b;  // declares b
};

...它声明了一个类名:

class Y;

...它包含不带初始值设定项或函数体的关键字:extern

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

...or 是 or 语句。typedefusing

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

现在,了解声明和定义之间的区别很重要的重要原因:一个定义规则。从 C++ 标准的第 3.2.1 节:

任何转换单元都不得包含任何变量、函数、类类型、枚举类型或模板的多个定义。

评论

1赞 RJFalconer 3/4/2014
“在类定义中声明一个静态成员” - 即使静态成员已初始化,也是如此,对吗?我们可以举个例子吗?struct x {static int b = 3; };
2赞 Kyle Strand 8/15/2014
@RJFalconer 你是对的;初始化不一定会把一个声明变成一个定义(与人们所期望的相反;当然,我觉得这很令人惊讶)。您对示例的修改实际上是非法的,除非也声明了。请参阅 stackoverflow.com/a/3536513/1858225daniweb.com/software-development/cpp/threads/140739/...bconst
2赞 Victor Zamanian 10/7/2014
这对我来说很有趣。根据您的回答,似乎在 C++ 中,声明也是一个定义(有例外),而在 C 标准中,它是从另一个角度表达的(C99,第 6.7 节,声明):“标识符的定义是该标识符的声明:[后跟不同情况的标准]”。我想,以不同的方式看待它。:)
1赞 Gab是好人 2/11/2016
声明是让编译器接受一个名称(告诉编译器该名称是合法的,该名称是有意引入的,而不是拼写错误)。定义是名称与其内容相关联的地方。链接器使用该定义将名称引用链接到名称的内容。
25赞 Steve Jessop 9/11/2009 #5

根据 C99 标准,6.7(5):

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

  • 对于对象,导致为该对象保留存储;
  • 对于函数,包括函数体;
  • 对于枚举常量或 typedef 名称,是 标识符。

根据 C++ 标准 3.1(2):

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

然后有一些例子。

有趣的是(或者不是,但我对此有点惊讶),是 C99 中的定义,但只是 C++ 中的声明。typedef int myint;

评论

0赞 sbi 9/11/2009
@onebyone:关于,这难道不意味着它可以在C++中重复,但在C99中不能吗?typedef
0赞 Steve Jessop 9/11/2009
这让我感到惊讶,就单个翻译单元而言,是的,存在这种差异。但很明显,typedef 可以在 C99 中以不同的翻译单元重复。C 没有像 C++ 那样明确的“一个定义规则”,所以它的规则只是允许它。C++ 选择将其更改为声明,但一个定义规则也列出了它适用于哪些类型的事物,而 typedefs 不是其中之一。因此,在 ODR 下的 C++ 中允许重复,即使 typedef 是一个定义。似乎不必要地挑剔。
0赞 Steve Jessop 9/11/2009
...但我猜 ODR 中的列表实际上列出了所有可能定义的东西。如果是这样,那么该列表实际上是多余的,只是为了提供帮助。
2赞 Steve Jessop 9/12/2009
@sbi:ODR规定“(1)任何翻译单元不得包含任何......类类型“和”(5)类类型可以有多个定义......在一个程序中,前提是每个定义出现在不同的翻译单元中“,然后是一些额外的要求,相当于”定义是相同的”。
1赞 Destructor 2/4/2016
@SteveJessop:根据 C11 标准更新您的答案,因为如您所知,C11 也允许重复 typedef。
2赞 user154171 9/11/2009 #6

您不能用最笼统的术语来说明,声明是一个标识符,其中没有分配存储,而定义实际上从声明的标识符分配存储吗?

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

评论

1赞 sbi 9/11/2009
您的定义本身并没有错,但是当涉及到函数定义时,“存储定义”总是显得很尴尬。关于模板:这是一个模板声明,这个也是如此。模板定义以相同的方式镜像类/函数定义。(请注意,模板名称不是类型函数名称。可以看到这一点的一个位置是,当您无法将一个模板作为另一个模板的类型参数传递时。如果要传递模板而不是类型,则需要模板模板参数。template<class T> struct foo;template<class T> void f();
0赞 9/11/2009
同意“存储定义”很尴尬,尤其是在函数定义方面。声明是 int foo(),定义是 int foo() {//这里的一些代码..}。我通常需要用我熟悉的概念来包裹我的小脑袋——“存储”就是这样一种方式,至少让我直截了当...... :)
54赞 Johannes Schaub - litb 9/12/2009 #7

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

T t;

这可以是定义或声明,具体取决于类型: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".

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

template <typename T>
struct X { 
  static int member; // declaration
};

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

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

最后一项声明不是一个定义。它是 的静态成员的显式专用化的声明。它告诉编译器:“如果涉及到实例化,则不要从主模板实例化成员的定义,而是使用在其他地方找到的定义”。要使其成为定义,您必须提供一个初始值设定项X<bool>X<bool>::member

template<>
int X<bool>::member = 1; // definition, belongs into a .cpp file.
165赞 plinth 9/12/2009 #8

宣言:“在某个地方,存在着一个foo。

定义:“......就在这里!

评论

4赞 Gab是好人 2/11/2016
声明是让编译器接受一个名称(告诉编译器该名称是合法的,该名称是有意引入的,而不是拼写错误)。定义是名称与其内容相关联的地方。链接器使用该定义将名称引用链接到名称的内容。
4赞 user565367 1/7/2011 #9

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

void  myfunction(); //this is simple declaration

void myfunction()
{
 some statement;    
}

这是函数 myfunction 的定义

评论

1赞 sbi 4/24/2013
那么类型和对象呢?
4赞 bjhend 4/18/2012 #10

经验法则:

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

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

评论

2赞 Lightness Races in Orbit 4/15/2013
这仅适用于对象。类型和功能呢?
-1赞 Puneet Purohit 1/3/2013 #11

声明意味着为变量提供名称和类型(在变量声明的情况下),例如:

int i;

或者给一个没有body的函数命名、返回类型和参数类型(在函数声明的情况下),例如:

int max(int, int);

而定义意味着为变量赋值(在变量定义的情况下),例如:

i = 20;

或者为函数提供/添加 body(functionality) 称为函数定义,例如:

int max(int a, int b)
{
   if(a>b)   return a;
   return b;  
}

很多时候的声明和定义可以一起完成,如下所示:

int i=20;

和:

int max(int a, int b)
{
    if(a>b)   return a;
    return b;    
} 

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

评论

0赞 Puneet Purohit 1/3/2013
如果将值/主体分配给变量/函数,而声明意味着为变量/函数提供名称、类型,则定义的实际平均值
0赞 Lightness Races in Orbit 4/15/2013
您可以定义某些内容,而无需为其赋值。
0赞 Puneet Purohit 4/15/2013
它是变量 X 的声明,而不是它的定义
2赞 Lightness Races in Orbit 4/15/2013
不,两者兼而有之。您将定义与初始化混淆了。
17赞 legends2k 6/27/2013 #12

C++11 更新

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

声明是一个定义,除非它声明了 a/n:

  • 不透明的枚举 -enum X : int;
  • template 参数 - T intemplate<typename T> class MyArray;
  • 参数声明 - XYint add(int x, int y);
  • 别名声明 -using IntVector = std::vector<int>;
  • 静态断言声明 -static_assert(sizeof(int) == 4, "Yikes!")
  • 属性声明(实现定义)
  • 空声明;

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

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

模板声明是一个声明。如果模板声明的声明定义了函数、类或静态数据成员,则该声明也是一种定义。

区分声明和定义的标准示例,我发现这些示例有助于理解它们之间的细微差别:

// 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赞 It'sPete 7/3/2013 #13

这听起来很俗气,但这是我能够将术语直截了当的最好方法:

宣言:图片托马斯·杰斐逊(Thomas Jefferson)发表演讲...“我特此声明,此 FOO 存在于此源代码中!!”

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

4赞 Santosh 3/13/2014 #14

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

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

声明是一种定义,除非:

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

定义是一种声明,除非:

  • 定义定义一个静态类数据成员,
  • 定义定义非内联成员函数。
0赞 achoora 11/13/2014 #15

当您使用 extern 存储类时,声明和定义的概念将形成一个陷阱,因为您的定义将位于其他位置,并且您在本地代码文件(页面)中声明变量。C 和 C++ 之间的一个区别是,在 C 中,声明通常在函数或代码页的开头完成。在 C++ 中,情况并非如此。您可以在您选择的地点申报。

评论

1赞 sbi 8/1/2015
这混淆了声明和定义,是完全错误的。
0赞 Jason K. 10/10/2016 #16

我最喜欢的例子是“int Num = 5”,这里的变量是 1。定义为 int 2。声明为 Num 和 3。以值 5 进行实例化。我们

  • 定义对象的类型,可以是内置的,也可以是类或结构。
  • 声明一个对象的名称,因此任何有名称的东西都被声明了,包括变量、函数等。

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

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

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

评论

0赞 Jason K. 10/10/2016
我不明白为什么这么多人对 sbi 的答案投了赞成票。我确实对 bjhend 的答案投了赞成票,它非常好、简洁、准确,而且比我的要及时得多。我很伤心地看到我是 4 年来第一个这样做的人。
9赞 SRIDHARAN 1/4/2017 #17

定义:

extern int a;      // Declaration 
int a;             // Definition
a = 10             // Initialization
int b = 10;        // Definition & Initialization

定义将变量与类型相关联并分配内存,而声明仅指定类型而不分配内存。当您想在定义之前引用变量时,声明会更有用。

*不要将定义与初始化混淆。两者是不同的,初始化为变量提供了价值。请参阅上面的示例。

以下是一些定义示例。

int a;
float b;
double c;

现在函数声明:

int fun(int a,int b); 

请注意函数末尾的分号,因此它表示它只是一个声明。编译器知道在程序中的某个地方,该函数将使用该原型进行定义。现在,如果编译器获得一个函数,请调用如下内容

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

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

请注意两个程序之间的差异。

计划 1

#include <stdio.h>
void print(int a)
{
     printf("%d",a);
}
main()
{
    print(5);
}

在这里,打印函数也被声明和定义。由于函数调用是在定义之后出现的。现在看下一个程序。

计划2

 #include <stdio.h>
 void print(int a); // In this case this is essential
 main()
 {
    print(5);
 }
 void print(int a)
 {
     printf("%d",a);
 }

这是必不可少的,因为函数调用先于定义,因此编译器必须知道是否存在任何此类函数。因此,我们声明将通知编译器的函数。

定义:

定义函数的这一部分称为定义。它说明了在函数中要做什么。

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

评论

3赞 Joey Pabalinas 2/12/2018
int a; //declaration; a=10; //definition这是完全错误的。在谈论自动存储持续时间对象(在函数定义中声明但未使用其他存储类说明符(如 extern)声明的对象)时,这些对象始终是定义。
0赞 Joey Pabalinas 2/12/2018
要理解的主要区别在于,声明是说“一个事物存在于具有这些特征(类型等)的某个地方”,而定义是说“我正在声明一个具有这些特征的事物,我也在这里实例化它。由于您无法像这样转发声明自动存储持续时间对象,因此它们将始终是定义。
0赞 Joey Pabalinas 2/12/2018
除了一些我总是忘记的奇怪的 typedef 极端情况外,一个经验法则是所有定义都是声明。想想吧;当你实例化一些东西时,你还需要告诉编译器这个东西存在,它的特征是什么?
0赞 SRIDHARAN 2/1/2020
根据您的第一条评论更新了答案。但是,我不同意这种评论“当你实例化某些东西时,你还需要告诉编译器该东西存在”。在实例化时,我们并不总是指定 lhs 的类型。例如:a =10。我们在这里没有指定任何“特征”。
2赞 hdante 5/10/2017 #18

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

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

int f(int x) { return 2*x; } // declaration and definition
4赞 princio 10/3/2017 #19

要理解声明和定义之间的区别,我们需要查看汇编代码:

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)

这只是定义:

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。

看到:

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

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

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

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

6赞 Karoly Nyisztor 2/21/2018 #20

要理解名词,让我们先关注动词。

声明 - 正式宣布;宣布

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

所以,当你声明某件事时,你只需告诉它是什么

// declaration
int sum(int, int);

此行声明一个 C 函数,该函数采用两个类型的参数并返回一个 .但是,您还不能使用它。sumintint

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

// definition
int sum(int x, int y)
{
    return x + y;
}
1赞 LinuxBabe 3/8/2018 #21

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

在 C 中,声明仅提供函数或变量存在的信息并给出其类型。对于函数声明,还可以提供有关其参数类型的信息。声明的目的是允许编译器正确处理对已声明变量和函数的引用。另一方面,定义实际上为变量分配存储或说明函数的作用。

0赞 Jeet Parikh 8/8/2018 #22

可执行文件的生成阶段:

(1) 预处理器 -> (2) 转换器/编译器 -> (3) 链接器

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

译者确保:What is What ? 表示声明

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

链接器确保 : where is what ? 表示定义

0赞 Brad Solomon 8/16/2019 #23

K&R(第二版)中散布着一些非常明确的定义;将它们放在一个地方并将它们作为一个整体阅读会有所帮助:

“定义”是指创建变量或分配存储变量的位置;“声明”是指陈述变量性质但没有分配存储的地方。[第33页]

...

区分外部变量的声明及其定义非常重要。声明宣布变量的属性(主要是其类型);定义还会导致存储被留出。 如果线条

int sp;
double val[MAXVAL]

出现在任何函数之外,它们定义外部变量和 ,导致存储被搁置,并用作该源文件其余部分的声明。spval

另一方面,线条

extern int sp;
extern double val[];

为源文件的其余部分声明,即 和 数组(其大小在其他地方确定),但它们不会创建变量或为它们保留存储空间。spintvaldouble

在构成源程序的所有文件中,外部变量必须只有一个定义。...数组大小必须与定义一起指定,但可以通过声明来指定。[第80-81页]extern

...

声明指定了对每个标识符的解释;它们不一定保留与标识符关联的存储。预留存储的声明称为定义。[第210页]

0赞 Sindhukumari P 10/16/2020 #24

声明是指在不赋值或对象的情况下创建基元或对象引用变量或方法。 int a; 最终 int a;

定义意味着分别分配值或对象 int a =10;

初始化意味着为相应的变量或对象分配内存。

0赞 sun1211 3/15/2021 #25

变量的声明用于向编译器通知以下信息:变量的名称、它所保存的值的类型以及它所采用的初始值(如果有)。即,声明提供了有关变量属性的详细信息。然而,变量的定义说明了变量的存储位置。也就是说,变量的内存是在变量定义期间分配的。

评论

0赞 Marco 12/22/2022
and the initial value对于声明,则不成立。变量声明永远不能有初始值设定项。
1赞 SridharKritha 5/25/2022 #26

从 C++ 标准文档添加定义和声明示例(摘自 3.1 声明和定义部分)

定义:

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

声明:

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 d
3赞 midhun p 8/4/2022 #27

宣言说“这东西存在于某个地方”

int sampleFunc(); // function
extern int car;  // variable

定义说“这个东西存在在这里;为它留下记忆”

int sampleFunc() {} // function
int car; // variable

对象的定义点,初始化是可选的,并说“这是这个东西的初始值”:

int car = 0; // variable