之间的区别是什么的定义,并宣布?
-
05-07-2019 - |
题
意义都躲开我。
解决方案
声明 引入标识符并描述其类型,无论是类型,对象还是函数。声明是 编译器需要 来接受对该标识符的引用。这些是声明:
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 ++标准认为struct x;
是声明和struct x {};
定义。 (换句话说, <!> quot;前向声明<!>“用词不当 ,因为C ++中没有其他形式的类声明。)
感谢 litb(Johannes Schaub)挖出他的一个实际章节和经文答案。
其他提示
来自C ++标准3.1节:
声明将名称引入翻译单元或重新声明之前引入的名称 声明。声明指定了这些名称的解释和属性。
下一段陈述(强调我的)声明是一个定义,除非......
...它声明了一个函数而没有指定函数<!>#8217; s body:
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
}
...或是typedef
或using
声明。
typedef long LONG_32; // declares LONG_32
using namespace std; // declares std
现在有一个很重要的原因,为什么理解声明和定义之间的区别很重要:一个定义规则。从C ++标准的第3.2.1节开始:
任何翻译单元都不得包含任何变量,函数,类类型,枚举类型或模板的多个定义。
声明:<!>“;某处,有一个foo。<!>”;
定义:<!>“; ......这里是!<!>”
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
,那么不要从主模板中实例化成员的定义,而是使用在其他地方找到的定义<!> quot;。要使其成为定义,您必须提供初始化程序
template<>
int X<bool>::member = 1; // definition, belongs into a .cpp file.
<强>声明强>
声明告诉编译器a 程序元素或名称存在。一个 声明引入一个或多个 命名为程序。声明可以 在程序中不止一次出现。 因此,阶级,结构, 枚举类型等 可以声明用户定义的类型 每个编译单元。
<强>定义强>
定义指定代码或数据 这个名字描述。名字必须是 在可以使用之前声明。
从C99标准,6.7(5):
宣言规定的解释和属性的一的标识符。一个 定义 一个标识符的声明,标识:
- 为对象,导致储存以保留,对象;
- 用一个功能,包括功能的身体;
- 枚举不变或typedef的名字,是(仅)的声明 标识符。
从C++标准,3.1(2):
一个宣言是一个 定义 除非宣布一个功能,而不指定功能的身体,它包含的外部说明符或有联系的规范和既不是一个初始化,也不是一个功能的身体,因此宣布一个静态数据成员在类声明,这是一个类名称的宣言,或者它是一个typedef宣言》,使用声明,或一种使用指令。
然后有一些例子。
这样有趣的是(或不是,但我略感到惊讶), typedef int myint;
是一个定义在C99,但只有《宣言》在C++。
从wiki.answers.com:
术语的声明装置(C)你是说的编译器种类、大小和在情况下的功能宣言》、类型和尺寸参数的任何变,或用户定义的类型或功能在您的节目。 没有 空间保留在存储器的任何可变的情况下宣言》。然而compiler知道有多少空间来的储备在情况变这种类型的创建。
例如,以下是所有声明:
extern int a;
struct _tagExample { int a; int b; };
int myFunc (int a, int b);
定义,另一方面意味着增加所有的东西,《宣言》,空间也保留在记忆。你可以说"定义=宣言》+的空间保留"举例如下定义:
int a;
int b = 0;
int myFunc (int a, int b) { return a + b; }
struct _tagExample example;
看看 答案.
C++11更新
因为我没有看到一个答案相关的C++11这里有一个。
一个宣言是一个 定义 除非它声明a/n:
- 不透明的enum
enum X : int;
- 模板参数 T 在
template<typename T> class MyArray;
- 参数宣言-- x 和 y 在
int 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 int a;
或extern "C" { ... };
- 静态数据成员在一类 x 在
class C { static int x; };
- 类/struct宣言》,
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
定义是指实际写入的函数<!> amp;声明意味着简单的声明功能 例如
void myfunction(); //this is simple declaration
和
void myfunction()
{
some statement;
}
这是函数myfunction的定义
经验法则:
一个 宣言 告诉编译器如何解释的变量的数据存储器中。这是需要每一个访问。
一个 定义 保留记忆,使可变现有的。这发生了一次前第一次访问。
声明:
int a; // this declares the variable 'a' which is of type 'int'
因此声明将变量与类型相关联。
以下是一些声明的例子。
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);
}
在此,声明并定义了print函数。因为函数调用是在定义之后发生的。现在看下一个程序。
计划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
有时,声明和定义被分组为一个这样的语句。
int a=10;
要理解名词,我们首先关注动词。
声明 - 正式宣布;宣布
定义 - 明确而完整地展示或描述(某人或某事)
因此,当您声明某些内容时,您只需告诉它是什么。
// declaration
int sum(int, int);
这一行声明一个名为sum
的C函数,该函数接受两个int
类型的参数并返回<=>。但是,你还不能使用它。
当你提供它的实际工作方式时,就是它的定义。
// definition
int sum(int x, int y)
{
return x + y;
}
要理解声明和定义之间的区别,我们需要查看汇编代码:
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)
声明没有等效指令,因为它不是要执行的东西。
此外,声明告诉编译器变量的范围。
我们可以说声明是编译器使用的信息,用于建立变量的正确使用以及某些内存属于某个变量的时间。
难道你不能用最一般的术语说明声明是一个标识符,其中没有分配存储空间,定义实际上是从声明的标识符中分配存储空间的?
一个有趣的想法 - 在类或函数与类型信息链接之前,模板无法分配存储。那么模板标识符是声明还是定义?它应该是一个声明,因为没有分配存储空间,并且您只是简单地“模板化”模板类或函数。
找到类似的答案在这里: 技术的采访的问题在C.
一个 宣言 提供名称的程序;一个 定义 提供了一个独特的描述的一个实体(例如类型、实例和功能)内的程序。声明可以重复在一定范围的,它引入了一个名称在一定的范围。
一个宣言是一个定义,除非:
- 《宣言》宣布一个功能,而未指定其主体,
- 《宣言》包含一个外部说明符和没有初始化或功能的身体,
- 《宣言》是《宣言》的一个静态的类数据的成员没有一个类的定义,
- 《宣言》是一类名称的定义,
一个定义是一个宣言,除非:
- 定义,定义了一个静态的类数据的成员,
- 定义,定义了一个非联件的功能。
这听起来真的很俗气,但这是我能够将这些条款保持在我脑海中的最佳方式:
宣言:图片托马斯杰斐逊发表演讲...... <!>“我特此声明,这个源代码存在于此源代码中!!! <!>
定义:描绘一本字典,你正在查找Foo及其实际含义。
声明为编译器提供符号名称。定义是为符号分配空间的声明。
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 )
在C中,声明仅提供函数或变量存在的信息并给出其类型。对于函数声明,也可以提供有关其参数类型的信息。声明的目的是允许编译器正确处理对声明的变量和函数的引用。另一方面,定义实际上为变量分配存储或说明函数的作用。
声明意味着为变量提供名称和类型(在变量声明的情况下),例如:
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;
}
在上述情况下,我们定义并声明变量i
和function max()
。
当您使用extern存储类时,声明和定义的概念将形成一个陷阱,因为您的定义将位于其他位置,并且您在本地代码文件(页面)中声明该变量。 C和C ++之间的一个区别是,在C中,声明通常在函数或代码页的开头完成。在C ++中,它不是那样的。您可以在您选择的地方申报。
我最喜欢的例子是"int Num=5"在这里,你的变量是1。定义为int2.宣布为Num和3。实例有价值的五个。我们
- 定义类型的对象,这可能是内在的或一类或结构中。
- 声明对象的名称,所以任何与一名已宣布其中包括变量、功能,等等。
一类或结构允许你改变对象如何将定义时,它是以后使用。例如
- 一个可以宣布一个异类变量或阵列是没有具体定义。
- 使用一个偏C++你可以限定对象,它没有宣布的名字。
当我们学会编程这两个方面往往是困惑,因为我们往往在同一时间。
可执行代的阶段:
(1)预处理器 - <!> gt; (2)翻译/编译器 - <!> gt; (3)链接器
在第2阶段(翻译器/编译器),我们的代码中的声明语句告诉编译器我们将来会使用这些东西,你可以在以后找到定义,意思是:
翻译确保:什么是什么?表示声明
和(3)阶段(链接器)需要定义来绑定事物
链接器确保:在哪里?表示定义