定义和声明有啥区别?

Posted

技术标签:

【中文标题】定义和声明有啥区别?【英文标题】:What is the difference between a definition and a declaration?定义和声明有什么区别? 【发布时间】:2009-09-11 12:27:12 【问题描述】:

两者的含义我都没有理解。

【问题讨论】:

坦率地说,我在学习哪个是哪个方面遇到了很多麻烦,所以我发现名字并不明显。我对含义没有问题,只是将哪些名称与含义相关联。 我们已经详细讨论过这个问题:***.com/questions/671925/… 不过,这不是一个重复的问题,因为这是关于 C/C++ 的问题,而其他问题通常是关于所有语言的,或者没有。它只是有重复的答案(因为在另一个问题中,一些答案选择忽略除 C 和/或 C++ 之外的所有语言)。 @DavidThornley 我使用了这个技巧:definition 给出了给定变量或函数的更精细 描述。为了记住这一点,我记得“定义”这个词的中间与“更精细”这个词有相似之处。 :) @MarcoLeogrande:或者“确定”! 【参考方案1】:

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

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++ 中的类 声明 与类 定义 不断出现(在其他问题的答案和 cmets 中),我将粘贴一个此处引用 C++ 标准。 在 3.1/2,C++03 说:

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

3.1/3 然后举几个例子。其中:

[例子: [...] 结构 S int a;诠释 b; ; // 定义 S、S::a 和 S::b [...] 结构 S; // 声明 S ——结束示例

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

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

【讨论】:

@unknown:要么你的编译器坏了,要么你错误地复制了 sbi 的代码。例如,N1124 中的 6.7.2(2):“所有引用相同对象或函数的声明应具有兼容的类型;否则,行为未定义。” @Brian: "extern int i;"说我是某个地方的int,不用担心。 “我;”表示i是一个int,它的地址和作用域在这里确定。 @Brian:你错了。 extern int i 是一个声明,因为它只是引入/指定了i。您可以在每个编译单元中拥有任意数量的extern int i。然而,int i 是一个定义。它表示整数在此翻译单元中的空间,并建议链接器将所有对i 的引用链接到此实体。如果你有更多或更少的这些定义,链接器会抱怨。 @Brian int i; 在文件/全局范围或函数范围内是 C 和 C++ 中的定义。在 C 中是因为它分配存储空间,而在 C++ 中是因为它没有 extern 说明符或链接规范。这些相当于同一件事,这就是 sbi 所说的:在这两种情况下,此声明都指定了该范围内对“i”的所有引用都必须链接到的对象。 @unknown,请注意您不能重新声明 class 范围内的成员:struct A double f(int, double); double f(int, double); ; 无效,当然。不过在其他地方是允许的。在某些地方您可以声明事物,但也不能定义:void f() void g(); 有效,但以下不是:void f() void g() ;。当涉及到模板时,什么是定义以及什么声明具有微妙的规则 - 请注意! +1 是一个很好的答案。【参考方案2】:

来自 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

...或者是typedefusing 语句。

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

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

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

【讨论】:

“在类定义中声明一个静态成员” - 即使静态成员已初始化也是如此,对吗?我们可以举个例子struct x static int b = 3; ;吗? @RJFalconer 你是对的;初始化确实不一定将声明转换为定义(与人们的预期相反;当然我发现这令人惊讶)。您对示例的修改实际上是非法的,除非b 也被声明为const。见***.com/a/3536513/1858225 和daniweb.com/software-development/cpp/threads/140739/…。 这对我来说很有趣。根据您的回答,似乎在 C++ 中,声明 also 是一个定义(有例外),而在 C 标准中,它是从另一个角度表述的(C99,第 6.7 节,声明): “标识符的定义是该标识符的声明:[遵循不同情况的标准]”。不同的方式来看待它,我想。 :) 声明是让编译器接受一个名字(告诉编译器这个名字是合法的,这个名字是有意引入的,不是错字)。定义是名称及其内容相关联的地方。链接器使用该定义将名称引用链接到名称的内容。【参考方案3】:

声明:“某处,存在一个 foo。”

定义:“……就在这里!”

【讨论】:

声明是让编译器接受一个名字(告诉编译器这个名字是合法的,这个名字是有意引入的,不是错字)。定义是名称及其内容相关联的地方。链接器使用该定义将名称引用链接到名称的内容。【参考方案4】:

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&lt;bool&gt; 的静态成员的显式特化声明。它告诉编译器:“如果要实例化X&lt;bool&gt;::member,则不要从主模板实例化成员的定义,而是使用在其他地方找到的定义”。为了使它成为一个定义,你必须提供一个初始化器

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

【讨论】:

【参考方案5】:

声明

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

定义

定义指定什么代码或数据 名称描述。名字必须是 在可以使用之前声明。

【讨论】:

嗯,不是说每个编译单元都可以定义类和枚举吗?至少我将类 definitions 放入我的标题中并将它们全部包含在内。呃,class foo ;一个类定义,不是吗? 是的。但是,“类 foo;”是一个声明。它告诉编译器 foo 是一个类。 “类富 ;”是一个定义。它准确地告诉编译器 foo 是什么类。 例外是可以在声明之前使用的类成员名称。 是的,我就是这个意思。因此,您可以执行以下操作: struct foo void b() f(); 无效 f(); ,即使尚未声明 f 也是可见的。以下也有效: struct foo void b(int = bar()); typedef int 条; ;。它在“所有函数体、默认参数、构造函数 ctor-initializers”中声明之前可见。不在返回类型中:( @litb:它在声明之前是不可见的,只是标识符的 use 被移到了声明后面。是的,我知道,在很多情况下效果都是一样的。但并非适用于所有情况,这就是为什么我认为我们应该使用精确的解释。 ——哎呀,等等。它在默认参数中可见吗?嗯,这肯定会对我的理解造成严重破坏。该死! 【参考方案6】:

来自 C99 标准,6.7(5):

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

对于一个对象,导致为该对象保留存储空间; 对于函数,包括函数体; 对于枚举常量或 typedef 名称,是(唯一的)声明 标识符。

来自 C++ 标准,3.1(2):

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

然后是一些例子。

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

【讨论】:

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

来自 wiki.answers.com:

术语声明意味着(在 C 中)您告诉编译器类型、大小以及在函数声明的情况下,任何变量的参数的类型和大小,或程序中用户定义的类型或函数。 No 在内存中为声明的任何变量保留空间。但是编译器知道在创建这种类型的变量时要保留多少空间。

例如,以下是所有声明:

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; 

见Answers。

【讨论】:

这也是错误的(虽然比其他的更接近):struct foo ; 是一个定义,而不是一个声明。 foo 的声明将是 struct foo;。由此,编译器不知道要为foo 对象保留多少空间。 @Marcin:sbi 是说“编译器知道在创建这种类型的变量时要保留多少空间”并不总是正确的。 struct foo; 是一个声明,但它不会告诉编译器 foo 的大小。我要补充一点,struct _tagExample int a; int b; ; 是一个定义。因此,在这种情况下,将其称为声明是一种误导。当然它是一个,因为所有定义都是声明,但您似乎暗示它不是定义。它是 _tagExample 的定义。 @Marcin Gil:这意味着“答案”维基并不总是准确的。我必须对这里的错误信息投反对票。 我们了解到,adatapost 引用的内容是真实的,但 (IMO) 并没有真正回答这个问题。 Marcin 引用的内容是错误的。引用标准是正确的并回答了问题,但很难做出正面或反面。 @David Thornley - 没问题 :) 这就是这个网站的意义所在。 我们选择并验证信息。【参考方案8】:

C++11 更新

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

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

不透明枚举 - enum X : int; 模板参数 - T in template&lt;typename T&gt; class MyArray; 参数声明 - xyint add(int x, int y); 别名声明 - using IntVector = std::vector&lt;int&gt;; 静态断言声明 - static_assert(sizeof(int) == 4, "Yikes!") 属性声明(实现定义) 空声明;

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

函数声明 - 添加int add(int x, int y); 包含声明或链接说明符的外部说明符 - extern int a;extern "C" ... ; 类中的静态数据成员 - class C static int x; ; 中的 x 类/结构声明 - struct Point; typedef 声明 - typedef int Int; 使用声明 - using std::cout; 使用指令 - 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

【讨论】:

【参考方案9】:

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

声明 - 正式宣布;宣布

定义 - 清楚完整地显示或描述(某人或某事)

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

// declaration
int sum(int, int);

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

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

// definition
int sum(int x, int y)

    return x + y;

【讨论】:

【参考方案10】:

定义:

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);

【讨论】:

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

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

void  myfunction(); //this is simple declaration

void myfunction()

 some statement;    

这是函数myfunction的定义

【讨论】:

那么类型和对象呢?【参考方案12】:

经验法则:

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

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

【讨论】:

这仅适用于对象。类型和函数呢?【参考方案13】:

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

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)

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

进一步的声明告诉编译器变量的范围。

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

【讨论】:

【参考方案14】:

在这里找到类似的答案:Technical Interview Questions in C。

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

声明就是定义,除非:

声明声明一个函数而不指定它的主体, 声明包含一个外部说明符,但没有初始化程序或函数体, 声明是没有类定义的静态类数据成员的声明, 声明是类名定义,

定义就是声明,除非:

定义定义了一个静态类数据成员, 定义定义了一个非内联成员函数。

【讨论】:

【参考方案15】:

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

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

【讨论】:

你的定义本身并没有错,但是当涉及到函数定义时,“存储定义”总是显得很尴尬。关于模板:template&lt;class T&gt; struct foo; 是模板声明template&lt;class T&gt; void f(); 也是。模板定义以相同的方式镜像类/函数定义。 (请注意,template name 不是 typefunction name。当您无法将模板传递为另一个模板的类型参数。如果要传递模板而不是类型,则需要模板模板参数。) 同意“存储定义”很尴尬,尤其是在函数定义方面。声明是 int foo() 并且定义是 int foo() //这里的一些代码..。我通常需要用我熟悉的概念来包裹我的小脑袋——“存储”是一种这样的方式,至少可以让我直截了当……:)【参考方案16】:

这听起来很俗气,但这是我能够在脑海中保持这些术语的最佳方式:

声明:图片 Thomas Jefferson 发表演讲...“我在此声明此 FOO 存在于此源代码中!!!”

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

【讨论】:

【参考方案17】:

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

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

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

【讨论】:

【参考方案18】:

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

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

【讨论】:

【参考方案19】: 变量的

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

【讨论】:

【参考方案20】:

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

【讨论】:

这混淆了声明和定义,是完全错误的。【参考方案21】:

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

定义对象的类型,可以是内置的,也可以是类或结构体。 声明对象的名称,因此任何具有名称的内容都已声明,包括变量、函数等。

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

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

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

【讨论】:

我不明白为什么这么多人赞成 sbi 的回答。我确实赞成 bjhend 的答案,它比我的答案非常好、简洁、准确且及时得多。看到自己是 4 年来第一个这样做的人,我很难过。【参考方案22】:

可执行文件生成的阶段:

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

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

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

和(3)阶段(链接器)需要定义来绑定东西

链接器确保:什么在哪里?表示定义

【讨论】:

【参考方案23】:

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

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

...

区分一个外部变量的声明和它的定义是很重要的。声明宣布变量的属性(主要是它的类型);定义也会导致存储空间被搁置。 如果行

int sp;
double val[MAXVAL]

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

另一方面,线条

extern int sp;
extern double val[];

声明源文件的其余部分 spint 并且 valdouble 数组(其大小在别处确定),但它们没有创建变量或为它们保留存储空间。

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

...

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

【讨论】:

【参考方案24】:

声明是在创建原始或对象引用变量或方法时没有分配值或对象。 诠释一个; 最终int a;

定义的意思是分别给值或对象赋值 int a =10;

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

【讨论】:

【参考方案25】:

声明是指给变量命名和类型(在变量声明的情况下),例如:

int i;

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

int max(int, int);

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

i = 20;

或向函数提供/添加主体(功能)称为函数定义,例如:

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()

【讨论】:

如果将值/主体分配给变量/函数,则定义的实际含义,而声明意味着为变量/函数提供名称、类型 你可以定义一些东西而不给它赋值。 它是变量 x 的声明而不是它的定义 不,两者都是。您将定义与初始化混淆了。

以上是关于定义和声明有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

c语言中,声明和定义有啥区别

C ++中变量的声明和定义有啥区别? [复制]

请问C++中啥是函数的定义性声明和函数的引用性声明,有啥区别

c语言中函数定义和声明有啥区别

头文件和源文件有啥区别呢?

C语言结构体中struct和typedef struct有啥区别?