定义和声明之间有什么区别?

1037
两者的意义都让我无法理解。

19
说实话,我在学习时很难区分哪个对应哪个名称,所以我觉得这些名称并不明显。我能理解意思,只是不知道该把哪个名称与其对应的意思联系起来。 - David Thornley
2
我们已经详细地讨论过这个问题:https://dev59.com/_nRB5IYBdhLWcg3wSVYI。 - dmckee --- ex-moderator kitten
1
一个更有趣的问题是“声明和原型之间的区别”:https://dev59.com/SW035IYBdhLWcg3wVuh1 - Mooing Duck
1
这是一篇不错的文章,解释了extern关键字和内存分配与声明/定义的关系:http://www.dreamincode.net/forums/topic/171468-declarations-vs-definitions/ - Griffin
1
这可能会有所帮助:http://www.cprogramming.com/declare_vs_define.html - barlop
可能是什么是 C++ 的定义,声明和赋值?的重复问题。 - TylerH
27个回答

4

定义意味着实际编写的功能,而声明意味着简单地声明函数。例如:

void  myfunction(); //this is simple declaration

and

void myfunction()
{
 some statement;    
}

这是函数myfunction的定义


1
那么类型和对象呢? - sbi

4
为了理解声明和定义之间的区别,我们需要查看汇编代码:
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)

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

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

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


4

经验法则:

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

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


2
这仅适用于对象。那么类型和函数呢? - Lightness Races in Orbit

4
在这里找到类似答案:C语言技术面试问题声明为程序提供一个名称; 定义为程序中的实体(例如类型、实例和函数)提供唯一描述。在给定作用域内可以重复声明,它在给定作用域内引入一个名称。
除非以下情况,否则声明即是定义:
  • 声明不指定其主体的函数,
  • 声明包含extern说明符且没有初始化项或函数主体,
  • 声明为静态类数据成员的声明而没有类定义,
  • 声明为类名定义,
除非以下情况,否则定义即是声明:
  • 定义了静态类数据成员,
  • 定义了非内联成员函数。

3

声明表示“这个东西在某个地方存在”

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

定义指“这件事物存在于这里;为其分配内存”

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

初始化是对象定义时的可选项,它表示“这个东西的初始值在这里”:

int car = 0; // variable

2

你能用最通俗易懂的方式阐述一下声明是指没有分配存储空间的标识符,而定义则实际上从已声明的标识符中分配存储空间吗?

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


1
你的定义并没有错,但是当涉及到函数定义时,“存储定义”似乎总是很奇怪。关于模板:这个template<class T> struct foo;是一个模板声明,这个template<class T> void f();也是如此。模板定义以同样的方式反映类/函数定义。 (请注意,_模板名称_不是_类型_或_函数名称_。您可以看到其中一个地方是当您无法将模板作为另一个模板的类型参数传递时。如果您想传递模板而不是类型,则需要使用模板模板参数。) - sbi
同意“存储定义”这个术语有些别扭,特别是在函数定义方面。声明是int foo(),而定义是int foo() {//一些代码...}。我通常需要用我熟悉的概念来包装我的小脑袋——“存储”就是其中一种让我至少能够清晰理解的方式... :) - user154171

2

声明向编译器展示符号名称。定义是分配符号空间的声明。

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

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

1

从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

1
这可能听起来很俗套,但这是我一直以来记住术语的最好方法:
声明:想象托马斯·杰斐逊发表演讲... "我在此宣布,这个Foo在源代码中存在!!!"
定义:想象一本词典,你正在查找Foo及其实际含义。

1
根据GNU C库手册(http://www.gnu.org/software/libc/manual/html_node/Header-Files.html
在C语言中,声明仅提供函数或变量的存在信息并给出其类型。对于函数声明,可能还会提供其参数类型的信息。声明的目的是允许编译器正确处理对已声明变量和函数的引用。另一方面,定义实际上为变量分配存储空间或说明函数的功能。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接